# source("utility.R")
source("R_functions.R")
source("R_data_prepocessing.R")

News headline

1st half 2020

AU_timeline %>% 
  filter(date <= ymd(20200515)) %>%
  arrange(date) %>% 
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         # point_position = 700 * nchar_scaled * (-1)^rowid,
         point_position = c(100,100,280,320,550,20,100,550,720,150,
                            240,880,400,300)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/1.8), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  # facet_wrap(~facet_var, strip.position="top",
  #            ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  labs(subtitle = "AU/NSW Covid-19 timeline, 1st half 2020") +
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

2nd half 2020

AU_timeline %>% 
  filter(date > ymd(20200515)) %>%
  arrange(date) %>% 
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         # point_position = 700 * nchar_scaled * (-1)^rowid,
         point_position = c(50,100,280,420,550,720,100,550,720,150,
                            240,780,830,300)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/3), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  # facet_wrap(~facet_var, strip.position="top",
  #            ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  labs(subtitle = "AU/NSW Covid-19 timeline, 2nd half 2020") +
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

Full

AU_timeline %>% 
  # filter(date >= ymd(20200220)) %>% 
  arrange(date) %>% 
  add_row(date = ymd(20200120), event="") %>%
  # add_row(date = ymd(20200220), event="") %>%
  add_row(date = ymd(20200331), event="") %>%
  add_row(date = ymd(20200401), event="") %>%
  add_row(date = ymd(20200630), event="") %>%
  add_row(date = ymd(20200701), event="") %>%
  add_row(date = ymd(20200930), event="") %>%
  add_row(date = ymd(20201001), event="") %>%
  # filter(nchar(event) < 230) %>% 
  # filter(region != "VIC") %>% 
  mutate(rowid = as.numeric(rownames(.))) %>% 
  mutate(date_gap = as.numeric(date-lag(date))) %>% 
  mutate(nchar = nchar(event), 
         nchar_scaled = (nchar-min(nchar))/(max(nchar)-min(nchar)), 
         point_position = 800 * nchar_scaled * (-1)^rowid,
         # point_position = c(100)*(-1)^rowid
         ) %>% 
  mutate(facet_var = quarter(date, with_year = T)) %>% 
  
  ggplot(aes(x=date, y=0)) + 
  geom_line() + 
  geom_point(aes(col=region)) +
  geom_segment(aes(x=date, xend=date, col=region,
                   y=0, yend=point_position)) +
  geom_point(aes(y=point_position, col=region), shape=1) +
  geom_text(aes(y=-10, 
                label=paste0(day(date), " ", 
                             month(date, label=T))), 
            angle=30, 
            vjust=1, hjust=1) + 
  geom_label(aes(label=str_wrap(paste0(date, ": ", event), nchar/2), alpha=.7,
                 # directions="y", min.segment.length = Inf,
                 x=date, y=point_position, col=region, vjust="outward")) +
  scale_x_date(date_breaks = "1 month", 
               date_labels = "%b %Y") + 
  facet_wrap(~facet_var, strip.position="top",
             ncol = 1, scales = "free_x") +
  # coord_flip() +
  ylim(-1200,1200) + 
  coord_cartesian(clip = "off") + 
  theme_void(base_size = 23) +
  theme(legend.position = "none", 
        # rect = element_rect(fill = "transparent"),
        plot.margin = unit(c(0, 2.3, 0, 2.3),"cm"),
        # plot.background = element_rect(fill = NULL)
        )

Time series

Daily

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(notification_date) %>% 
  ggplot(aes(x=notification_date , y=n)) + 
  # geom_point() + 
  geom_line() + 
  ylab("Count of cases") + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (SYD)") + 
  annotate("text", x=ymd(20200505), y=60, size=3.3, col="darkred", 
           label="1st outbreak \n (Bondi beach, \nSouth Eastern \nSydney, 2026)") + 
  annotate("text", x=ymd(20200815), y=25, size=3.3, col="darkred", 
           label="2nd outbreak \n (Westmead & Liverpool, \nWestern Sydney, 2145)") + 
  annotate("text", x=ymd(20210101), y=35, size=3.3, col="darkred", 
           label="3rd outbreak \n (Avalon beach, Northern Sydney, 2107)") + 
  ggl()

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(lhd_2010_name, notification_date) %>% 
  ggplot(aes(x=notification_date , y=n, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Daily new confirmed Covid-19 cases (SYD)") + 
  ggl(lp = "right")

Cumulative

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(lhd_2010_name = ifelse(lhd_2010_name == "Sydney", "Sydney (around CBD)", 
                                lhd_2010_name)) %>% 
  # mutate(lhd_2010_name = ifelse(is.na(lhd_2010_name), "Unknown", lhd_2010_name)) %>%
  count(lhd_2010_name, notification_date) %>% 
  group_by(lhd_2010_name) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab = ifelse(notification_date == max(notification_date, na.rm=T), 
                      lhd_2010_name, NA)) %>% 
  
  ggplot(aes(x=notification_date , y=accumulated_cases, col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text_repel(aes(label=lab), size=4, hjust=-.1, min.segment.length = 10) + 
  # facet_wrap(~lhd_2010_name) + 
  labs(subtitle = "Accumulated confirmed Covid-19 cases (SYD), by Local Health District (LHD)") + 
  # xlim(c(0,550)) +
  ggl(base_size=12, lp = "none") 

confirmed_cases %>% 
  mutate(lhd_2010_name = ifelse(lhd_2010_name == "Sydney", "Sydney (around CBD)", 
                                lhd_2010_name)) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  # filter(lhd_2010_name %in% c("South Eastern Sydney", 
  #                          "Northern Sydney", 
  #                          "Western Sydney", 
  #                          "South Western Sydney", 
  #                          "Sydney") | is.na(lhd_2010_name)) %>% 
  count(lhd_2010_name, postcode, notification_date) %>% 
  group_by(lhd_2010_name, postcode) %>% 
  mutate(days_since_first_case = notification_date - min(notification_date)) %>% 
  mutate(accumulated_cases = cumsum(n)) %>% 
  mutate(lab=ifelse(notification_date == max(notification_date), postcode, NA)) %>% 
  
  ggplot(aes(x=notification_date , y=accumulated_cases, 
             group=postcode,
             col=lhd_2010_name)) + 
  # geom_point() + 
  geom_line() + 
  geom_text(aes(label=lab), size=3, hjust="outward") + 
  facet_wrap(~lhd_2010_name) +
  labs(subtitle = "Accumulated confirmed Covid-19 cases (SYD), by postcode (POA)") + 
  # xlim(c(0,550)) +
  ggl(base_size=12, lp = "none", ) + 
  theme(strip.text.x = element_text(size = 12))

Map

Looks like each postcode (POA) can only belong to one LGA, which is not the case for SA2

confirmed_cases %>% 
  distinct(postcode, lga_name19) %>% 
  count(postcode) %>% 
  summarise(max(n)) %>% 
  pull()
[1] 1

LGA

confirmed_cases %>% 
  filter(lga_name19 %in% SYD_LGA$LGA_NAME19) %>% 
  count(lga_name19, name="Total_cases") %>% 
  rename(LGA_NAME19 = lga_name19) %>% 
  mutate(LGA_NAME19 = fct_reorder(LGA_NAME19, Total_cases)) %>% 
  plot_map_TL(SYD_LGA, "LGA_NAME19", "Total_cases", 
           "Total Covid-19 cases by LGA (SYD)", show_count = T)

POA

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD)", 
           show_count = T, label_size = 2)

confirmed_cases %>%
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>%
  count(postcode, name="Total_cases") %>%
  rename(POA_NAME16 = postcode) %>%
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>%
  mutate(cluster_origin = ifelse(POA_NAME16 %in% c("2026", "2145", "2107"),
                                 "cluster_origin", "") %>% as.factor) %>%
  plot_map_factor_TL(SYD_POA, "POA_NAME16", "Total_cases", "cluster_origin",
              "Total Covid-19 cases by POA (SYD), highlighted by cluster origin",
              show_count = T, label_size = 2)

confirmed_cases %>% 
  filter(!(postcode %in% c(2026, 2145, 2170))) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD), excluding top 3 POA", 
           show_count = T, label_size = 2)

Note

Northern Beaches has many postcodes which result in more diluted choropleth by POA.

confirmed_cases %>% 
  distinct(lga_name19, postcode) %>% 
  count(lga_name19, name="Number_of_postcodes") %>% 
  left_join(confirmed_cases %>% count(lga_name19, name="Total_cases"), 
            by="lga_name19") %>% 
  slice_max(n=30, order_by = Total_cases) %>% 
  gather(key, value, -lga_name19) %>% 
  ggplot(aes(x=reorder(lga_name19, value), y=value)) + 
  geom_col() + 
  facet_wrap(~key, scales = "free_x") + 
  coord_flip() + 
  xlab("") + ylab("") + 
  ggl()

Map overtime cumulative

By quarter

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>% 
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_cases", 
           "Total accumulated Covid-19 cases by POA (SYD), by quarter", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme_map_facet_TL + 
  theme()

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0(year_quarter, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(
    SYD_POA[SYD_POA$POA_NAME16 %in% as.character(
      confirmed_cases$postcode) ,], .01), 
              "POA_NAME16", "Accumulated_share", 
           "Total Covid-19 cases by POA (SYD)", 
           return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme_map_facet_TL

By week Mar-May 2020

Accumulated cases

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_cases", 
              "Total Covid-19 cases by POA (SYD)", 
              return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme_map_facet_TL + theme(legend.position = c(.83, .15))

Accumulated share

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  plot_map_TL(rmapshaper::ms_simplify(SYD_POA, .01), 
              "POA_NAME16", "Accumulated_share", 
              "Total Covid-19 cases by POA (SYD)", 
              return_obj="map") + 
  facet_wrap(~facet_var) + 
  theme_map_facet_TL + theme(legend.position = c(.83, .15))

Distribution of share overtime

By quarter

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  complete(year_quarter, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  ungroup() %>% 
  
  ggplot(aes(x=year_quarter, y=Accumulated_cases, 
             fill=Accumulated_cases > 50,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(year_quarter = paste(year(notification_date), "Q",
                             quarter(notification_date), sep="-")) %>% 
  count(year_quarter, postcode, name="Total_cases") %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  ungroup() %>% 
  complete(year_quarter, postcode) %>% 
  replace_na(list(Accumulated_cases=0)) %>% 
  group_by(year_quarter) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, na.rm=T))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(year_quarter))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~year_quarter, nrow = 1) + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

By week

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=isoweek, y=Accumulated_cases, 
             fill=Accumulated_cases > 20,
             group=as.factor(POA_NAME16))) + 
  geom_col(col="white", size=.1) + 
  ggx(round, pbn=12) +
  ggf(fc = DC[2:1]) + 
  ggl("top", lt = T)

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  filter(year(notification_date) == 2020, 
         # month(notification_date) %in% 3:5, 
         isoweek(notification_date) %in% 10:23) %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  mutate(isoweek = isoweek(notification_date)) %>% 
  count(isoweek, postcode, name="Total_cases") %>% 
  complete(isoweek, postcode, fill = list(Total_cases=0)) %>% 
  group_by(postcode) %>% 
  mutate(Accumulated_cases = cumsum(Total_cases)) %>% 
  group_by(isoweek) %>% 
  mutate(Accumulated_share = (Accumulated_cases/sum(Accumulated_cases, 
                                                    na.rm=T))) %>%
  mutate(facet_var = paste0("week ", isoweek, 
                            "\nAccumulated: ", 
                            comma(sum(Accumulated_cases)))) %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  ungroup() %>% 
  filter(!is.na(isoweek)) %>% 
  
  ggplot(aes(x=Accumulated_share, fill=as.factor(isoweek))) + 
  # geom_density() + 
  geom_histogram() + 
  facet_wrap(~isoweek, nrow = 3, labeller = "label_both") + 
  xlim(0,.03) + 
  ylim(0,40) +
  ggl("none")

Local POI

Public transport

confirmed_cases %>% 
    filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
    count(postcode, name="Total_cases") %>% 
    rename(POA_NAME16 = postcode) %>% 
    mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
    plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", fill_col = "grey33",
                "Total Covid-19 cases by POA (SYD), with public transport", 
                show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.8) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.8) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.8) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.8) +
  ggc(c("deepskyblue", "red", "darkgreen", "orange")) + 
  guides(col=guide_legend(title="Transport_mode")) + 
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  coord_cartesian(xlim = c(150.7, 151.48), ylim = c(-34.1, -33.5)) +
  theme_void() +
  theme(legend.position = c(.9,.35))

Hospitals, Schools, Supermarket

bind_rows(
  SYD_shops %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
  SYD_supermarkets %>% select(lon, lat) %>% 
    rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
  SYD_hospitals %>% select(Longitude, Latitude) %>% 
    rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
  rbind(SYD_sschools %>% select(Long, Lat),
        SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
) %>% 
  ggplot() +  
  geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
           aes(map_id = id), map = tidy(SYD_POA), 
           col="grey50", size=.2, fill="white") +
  geom_jitter(aes(x=Long, y=Lat, col=obj), size=.8, alpha=.5) + 
  stat_density2d(aes(x=Long, y=Lat, 
                     fill=..level.., alpha=..level.., col=obj),
                 binwidth = 1.2, geom="polygon", size=.23) + 
  facet_wrap(~obj) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "deepskyblue", "darkblue", "darkgreen")) + 
  theme_void() +
  theme(legend.position = "none", 
        legend.title = element_blank(), 
        strip.text = element_text(size=15))

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", fill_col = "grey33",
              "Total Covid-19 cases by POA (SYD), overlayed with hospitals, schools, shopping centres & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .3, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("darkred", "darkblue", "darkorange", "darkgreen")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.25), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

POI combined

confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", fill_col = "grey33",
              "Total Covid-19 cases by POA (SYD), with hospitals, schools & supermarkets", 
              show_count = T, label_size = 2, return_obj = "map") +
  geom_line(data = SYD_trains, 
            aes(x=lon, y=lat, col="Train",
                group = `Railway line(s)`),
            size=.8) +
  geom_line(data = SYD_ferries, 
            aes(x=lon, y=lat, col="Ferry"),
             size=.8) +
  geom_line(data = SYD_lightrails, 
            aes(x=lon, y=lat, col="Lightrail"),
             size=.8) +
  geom_line(data = SYD_metro, 
            aes(x=lon, y=lat, col="Metro"),
             size=.8) +
  
  # geom_map(data = SYD_POA, inherit.aes = FALSE, alpha=.85,
  #          aes(map_id = id), map = tidy(SYD_POA), 
  #          col="grey50", size=.3, fill="white") +
  geom_jitter(data = bind_rows(
    SYD_shops %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Shopping centres"), 
    SYD_supermarkets %>% select(lon, lat) %>% 
      rename(Long = lon, Lat = lat) %>% mutate(obj = "Supermarkets"), 
    SYD_hospitals %>% select(Longitude, Latitude) %>% 
      rename(Long = Longitude, Lat = Latitude) %>% mutate(obj = "Hospitals"), 
    rbind(SYD_sschools %>% select(Long, Lat),
          SYD_pschools %>% select(Long, Lat)) %>% mutate(obj = "Schools")
  ), 
  size = 1, alpha = .3, aes(x=Long, y=Lat,col=obj)) +
  expand_limits(x = tidy(SYD_POA)$long, y = tidy(SYD_POA)$lat) +
  xlim(150.7,151.48) + ylim(-34.1,-33.5) +
  # scale_fill_gradient(low="white", high=DC[7]) + 
  scale_alpha_continuous(range = c(0,.3)) + 
  ggc(fc = c("deepskyblue", "darkblue", "red", "darkgreen", 
             "darkblue", "red", "darkgreen", "orange")) + 
  guides(color = guide_legend(override.aes = list(size=3), 
                              title="POI")) + 
  theme_void() +
  theme(legend.position = c(.9,.4), 
        # legend.title = element_blank(), 
        strip.text = element_text(size=15))

POI count QA

grid.arrange(
n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_hospitals) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_hospitals)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_hospitals", 
              "Number of hospitals by POA", 
              show_count = T, fill_col = "darkred", 
              return_obj = "map"), 
n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_schools) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_schools)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_schools", 
              "Number of schools by POA", 
              show_count = T, fill_col = "deepskyblue", 
              return_obj = "map"), 
n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_supermarkets) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_supermarkets)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_supermarkets", 
              "Number of supermarkets by POA", 
              show_count = T, fill_col = "darkgreen", 
              return_obj = "map"), 
n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_shoppingCentres) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_shoppingCentres)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_shoppingCentres", 
              "Number of shopping centres by POA", 
              show_count = T, fill_col = "black", 
              return_obj = "map"), 
n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_publicTransports ) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_publicTransports )) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_publicTransports", 
              "Number of public transports by POA", 
              show_count = T, fill_col = "darkorange", 
              return_obj = "map"), 
confirmed_cases %>% 
  filter(as.character(postcode) %in% SYD_POA$POA_NAME16) %>% 
  count(postcode, name="Total_cases") %>% 
  rename(POA_NAME16 = postcode) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), Total_cases)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "Total_cases", 
           "Total Covid-19 cases by POA (SYD)", 
           show_count = T, label_size = 2, 
              return_obj = "map"), 
ncol=2)

Hospital

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_hospitals) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_hospitals)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_hospitals", 
              "Number of hospitals by POA", 
              show_count = T, fill_col = "darkred")

Schools

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_schools) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_schools)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_schools", 
              "Number of schools by POA", 
              show_count = T, fill_col = "deepskyblue")

Supermarkets

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_supermarkets) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_supermarkets)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_supermarkets", 
              "Number of supermarkets by POA", 
              show_count = T, fill_col = "darkgreen")

Shopping centres

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_shoppingCentres) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_shoppingCentres)) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_shoppingCentres", 
              "Number of shopping centres by POA", 
              show_count = T, fill_col = "black")

Public transports

n_poi_by_POA %>% 
  filter(POA_NAME16 != "Unknown") %>% 
  # gather(key, value, -POA_NAME16) %>% 
  select(POA_NAME16, n_publicTransports ) %>% 
  mutate(POA_NAME16 = fct_reorder(POA_NAME16, n_publicTransports )) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", "n_publicTransports", 
              "Number of public transports by POA", 
              show_count = T, fill_col = "darkorange")

Census data mapping

plot_census_map <- function(VAR, COLOR) {
  census_feature_by_POA %>% 
  mutate(across(-POA_CODE_2016, ~round(.x, 1))) %>% 
  mutate(POA_NAME16 = as.character(POA_CODE_2016)) %>% 
  mutate(POA_NAME16 = fct_reorder(as.factor(POA_NAME16), .data[[VAR]])) %>% 
  plot_map_TL(SYD_POA, "POA_NAME16", VAR, 
           paste0(VAR, " by POA (SYD)"), fill_col = COLOR, 
           show_count = F, label_size = 2, return_obj = "map")
}

grid.arrange(
plot_census_map("high_income", "darkorange")
,plot_census_map("p_income", "grey23")
,plot_census_map("chinese_p", "darkred")
,plot_census_map("non_english_n", "darkgreen")
,plot_census_map("rent_distress", "darkblue")
,plot_census_map("unit", "deepskyblue")
, ncol=2)

Gravity

South Eastern SYD (2026)

Radial distance

(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_hospitals") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_schools") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) |
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_supermarkets") + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_shoppingCentres") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_publicTransports") + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2026", "combined_index") + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
)

Travel time distance

(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7) |
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
plot_gravity_map_TL(n_poi_by_POA, "2026", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2026", "combined_index", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151.1,151.33) + ylim(-34,-33.7)
)

Western SYD (2145)

Radial distance

(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_hospitals") | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_schools") |
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_supermarkets")
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_shoppingCentres") | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_publicTransports") | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2145", "combined_index")
)

Travel time distance

(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) |
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) | 
plot_gravity_map_TL(n_poi_by_POA, "2145", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2145", "combined_index", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
)

Nothern SYD (2107)

Radial distance

(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_hospitals") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_schools") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) |
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_supermarkets") + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_shoppingCentres") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_publicTransports") + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2107", "combined_index") + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
)

Travel time distance

(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5) |
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
) /
(
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
plot_gravity_map_TL(n_poi_by_POA, "2107", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5) | 
n_poi_by_POA %>% 
  mutate(combined_index = 
           normalised_n_hospitals +
           normalised_n_schools +
           normalised_n_supermarkets +
           normalised_n_shoppingCentres +
           normalised_n_publicTransports
  ) %>% plot_gravity_map_TL("2107", "combined_index", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000)) + 
  xlim(151,151.4) + ylim(-33.9,-33.5)
)

Suggested “high-risk” area

South Eastern SYD (2026)

bind_rows(
calc_gravity_TL(n_poi_by_POA, "2026", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2026", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2026", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2026", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2026", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
) %>% 
  group_by(target, source) %>% 
  summarise(risk_factor = sum(gravity_rank)) %>% 
  # slice_max(risk_factor, n=11) %>% 
  # pdf()
  
  left_join(
    confirmed_cases %>% 
      filter(notification_date < ymd(20200701)) %>% 
      count(postcode, name = "total_cases") %>% 
      mutate(source = as.character(postcode)), 
    by="source"
  ) %>% 
  mutate(text_lab = ifelse(total_cases >= 30, source, NA)) %>% 
  ggplot(aes(x=risk_factor, y=total_cases)) + 
  geom_point() + 
  stat_smooth() + 
  geom_text_repel(aes(label=text_lab)) + 
  labs(subtitle = "Based on total cases before date 2020-07-01") + 
  ggl(base_size=12)

Western SYD (2145)

bind_rows(
calc_gravity_TL(n_poi_by_POA, "2145", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2145", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2145", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2145", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2145", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
) %>% 
  group_by(target, source) %>% 
  summarise(risk_factor = sum(gravity_rank)) %>% 
  # slice_max(risk_factor, n=11) %>%
  # pdf()
  left_join(
    confirmed_cases %>% 
      filter(notification_date >= ymd(20200701), 
             notification_date < ymd(20201101)) %>% 
      count(postcode, name = "total_cases") %>% 
      mutate(source = as.character(postcode)), 
    by="source"
  ) %>% 
  mutate(text_lab = ifelse(total_cases >= 15, source, NA)) %>% 
  ggplot(aes(x=risk_factor, y=total_cases)) + 
  geom_point() + 
  stat_smooth() + 
  geom_text_repel(aes(label=text_lab)) + 
  labs(subtitle = "Based on total cases between date 2020-07-01 and 2020-12-01") + 
  ggl(base_size=12)

Nothern SYD (2107)

bind_rows(
calc_gravity_TL(n_poi_by_POA, "2107", "n_hospitals", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2107", "n_schools", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2107", "n_supermarkets", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2107", "n_shoppingCentres", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
,calc_gravity_TL(n_poi_by_POA, "2107", "n_publicTransports", 
                    dist_matrix = SYD_POA_mapdist %>% mutate(dist = dist/1000))
) %>% 
  group_by(target, source) %>% 
  summarise(risk_factor = sum(gravity_rank)) %>% 
  # slice_max(risk_factor, n=11) %>% 
  # pdf()
  left_join(
    confirmed_cases %>% 
      filter(notification_date >= ymd(20201101)) %>% 
      count(postcode, name = "total_cases") %>% 
      mutate(source = as.character(postcode)), 
    by="source"
  ) %>% 
  mutate(text_lab = ifelse(total_cases >= 15, source, NA)) %>% 
  ggplot(aes(x=risk_factor, y=total_cases)) + 
  geom_point() + 
  stat_smooth() + 
  geom_text_repel(aes(label=text_lab)) +
  labs(subtitle = "Based on total cases after date 2020-12-01") + 
  ggl(base_size=12)

Gravity parameters

SYD_POA_mapdist %>% 
  filter(target == "2145") %>% 
  left_join(n_poi_by_POA, by=c("source"="POA_NAME16")) %>% 
  left_join(n_poi_by_POA %>% filter(POA_NAME16 == "2145"), 
            suffix = c("","_target"), 
            by=c("target"="POA_NAME16")) %>% 
  left_join(confirmed_cases %>% 
              filter(notification_date >= ymd(20200701), 
                     notification_date < ymd(20201101)) %>% 
              count(postcode, name="Total_cases") %>% 
              mutate(source = as.character(postcode)), by="source") %>% 
  mutate(total_normalised_mass_source = 
           normalised_n_hospitals + 
           normalised_n_schools + 
           normalised_n_supermarkets + 
           normalised_n_shoppingCentres + 
           normalised_n_publicTransports) %>% 

  lm(log(Total_cases + 0.01) ~ 
       # log(total_normalised_mass_source + 0.01) + 
       log(n_hospitals + 0.01) +
       log(n_schools + 0.01) +
       log(n_supermarkets + 0.01) +
       log(n_shoppingCentres + 0.01) +
       log(n_publicTransports + 0.01) +
       log(n_hospitals + 0.01) +
       log(dist + 0.01), data=.) %>% 
  summary()

Call:
lm(formula = log(Total_cases + 0.01) ~ log(n_hospitals + 0.01) + 
    log(n_schools + 0.01) + log(n_supermarkets + 0.01) + log(n_shoppingCentres + 
    0.01) + log(n_publicTransports + 0.01) + log(n_hospitals + 
    0.01) + log(dist + 0.01), data = .)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.46174 -0.64127 -0.08704  0.46585  1.97683 

Coefficients:
                                Estimate Std. Error t value Pr(>|t|)    
(Intercept)                     1.657080   0.432004   3.836 0.000213 ***
log(n_hospitals + 0.01)        -0.027305   0.035916  -0.760 0.448784    
log(n_schools + 0.01)           0.230516   0.103446   2.228 0.027967 *  
log(n_supermarkets + 0.01)      0.062173   0.040671   1.529 0.129319    
log(n_shoppingCentres + 0.01)  -0.004801   0.041027  -0.117 0.907070    
log(n_publicTransports + 0.01) -0.052132   0.035630  -1.463 0.146386    
log(dist + 0.01)               -0.378727   0.097518  -3.884 0.000179 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.843 on 106 degrees of freedom
  (101 observations deleted due to missingness)
Multiple R-squared:  0.224, Adjusted R-squared:  0.1801 
F-statistic: 5.099 on 6 and 106 DF,  p-value: 0.0001232
LS0tDQp0aXRsZTogIlNZRCBDb3ZpZC0xOSBjYXNlcyBFREEiDQphdXRob3I6ICJUb255IExpdSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Kb3B0aW9ucyhzY2lwZW49OTk5LCBleHByZXNzaW9ucz01MDAwMCwgDQogICAgICAgIERULm9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzY3JvbGxYID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZG9tID0gJ0JmcnRpcCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCdjb3B5JywgJ2NzdicsICdleGNlbCcsICdwZGYnLCAncHJpbnQnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9XaWR0aCA9IFRSVUUpKSAgDQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVCwgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9NCkNCmtuaXRyOjpvcHRzX2tuaXQkc2V0KGRldi5hcmdzID0gbGlzdCh0eXBlID0gImNhaXJvIiksIHByb2dyZXNzPUZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KIyBzb3VyY2UoInV0aWxpdHkuUiIpDQpzb3VyY2UoIlJfZnVuY3Rpb25zLlIiKQ0Kc291cmNlKCJSX2RhdGFfcHJlcG9jZXNzaW5nLlIiKQ0KYGBgDQoNCg0KIyBOZXdzIGhlYWRsaW5lIHsudGFic2V0fQ0KIyMgMXN0IGhhbGYgMjAyMA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEyfQ0KQVVfdGltZWxpbmUgJT4lIA0KICBmaWx0ZXIoZGF0ZSA8PSB5bWQoMjAyMDA1MTUpKSAlPiUNCiAgYXJyYW5nZShkYXRlKSAlPiUgDQogICMgZmlsdGVyKG5jaGFyKGV2ZW50KSA8IDIzMCkgJT4lIA0KICAjIGZpbHRlcihyZWdpb24gIT0gIlZJQyIpICU+JSANCiAgbXV0YXRlKHJvd2lkID0gYXMubnVtZXJpYyhyb3duYW1lcyguKSkpICU+JSANCiAgbXV0YXRlKGRhdGVfZ2FwID0gYXMubnVtZXJpYyhkYXRlLWxhZyhkYXRlKSkpICU+JSANCiAgbXV0YXRlKG5jaGFyID0gbmNoYXIoZXZlbnQpLCANCiAgICAgICAgIG5jaGFyX3NjYWxlZCA9IChuY2hhci1taW4obmNoYXIpKS8obWF4KG5jaGFyKS1taW4obmNoYXIpKSwgDQogICAgICAgICAjIHBvaW50X3Bvc2l0aW9uID0gNzAwICogbmNoYXJfc2NhbGVkICogKC0xKV5yb3dpZCwNCiAgICAgICAgIHBvaW50X3Bvc2l0aW9uID0gYygxMDAsMTAwLDI4MCwzMjAsNTUwLDIwLDEwMCw1NTAsNzIwLDE1MCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAyNDAsODgwLDQwMCwzMDApKigtMSlecm93aWQNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcXVhcnRlcihkYXRlLCB3aXRoX3llYXIgPSBUKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9MCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoYWVzKGNvbD1yZWdpb24pKSArDQogIGdlb21fc2VnbWVudChhZXMoeD1kYXRlLCB4ZW5kPWRhdGUsIGNvbD1yZWdpb24sDQogICAgICAgICAgICAgICAgICAgeT0wLCB5ZW5kPXBvaW50X3Bvc2l0aW9uKSkgKw0KICBnZW9tX3BvaW50KGFlcyh5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uKSwgc2hhcGU9MSkgKw0KICBnZW9tX3RleHQoYWVzKHk9LTEwLCANCiAgICAgICAgICAgICAgICBsYWJlbD1wYXN0ZTAoZGF5KGRhdGUpLCAiICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb250aChkYXRlLCBsYWJlbD1UKSkpLCANCiAgICAgICAgICAgIGFuZ2xlPTMwLCANCiAgICAgICAgICAgIHZqdXN0PTEsIGhqdXN0PTEpICsgDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsPXN0cl93cmFwKHBhc3RlMChkYXRlLCAiOiAiLCBldmVudCksIG5jaGFyLzEuOCksIGFscGhhPS43LA0KICAgICAgICAgICAgICAgICAjIGRpcmVjdGlvbnM9InkiLCBtaW4uc2VnbWVudC5sZW5ndGggPSBJbmYsDQogICAgICAgICAgICAgICAgIHg9ZGF0ZSwgeT1wb2ludF9wb3NpdGlvbiwgY29sPXJlZ2lvbiwgdmp1c3Q9Im91dHdhcmQiKSkgKw0KICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAiMSBtb250aCIsIA0KICAgICAgICAgICAgICAgZGF0ZV9sYWJlbHMgPSAiJWIgJVkiKSArIA0KICAjIGZhY2V0X3dyYXAofmZhY2V0X3Zhciwgc3RyaXAucG9zaXRpb249InRvcCIsDQogICMgICAgICAgICAgICBuY29sID0gMSwgc2NhbGVzID0gImZyZWVfeCIpICsNCiAgIyBjb29yZF9mbGlwKCkgKw0KICB5bGltKC0xMjAwLDEyMDApICsgDQogIGNvb3JkX2NhcnRlc2lhbihjbGlwID0gIm9mZiIpICsgDQogIGxhYnMoc3VidGl0bGUgPSAiQVUvTlNXIENvdmlkLTE5IHRpbWVsaW5lLCAxc3QgaGFsZiAyMDIwIikgKw0KICB0aGVtZV92b2lkKGJhc2Vfc2l6ZSA9IDIzKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgICAgICMgcmVjdCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksDQogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDIuMywgMCwgMi4zKSwiY20iKSwNCiAgICAgICAgIyBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5VTEwpDQogICAgICAgICkNCmBgYA0KDQojIyAybmQgaGFsZiAyMDIwDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTJ9DQpBVV90aW1lbGluZSAlPiUgDQogIGZpbHRlcihkYXRlID4geW1kKDIwMjAwNTE1KSkgJT4lDQogIGFycmFuZ2UoZGF0ZSkgJT4lIA0KICAjIGZpbHRlcihuY2hhcihldmVudCkgPCAyMzApICU+JSANCiAgIyBmaWx0ZXIocmVnaW9uICE9ICJWSUMiKSAlPiUgDQogIG11dGF0ZShyb3dpZCA9IGFzLm51bWVyaWMocm93bmFtZXMoLikpKSAlPiUgDQogIG11dGF0ZShkYXRlX2dhcCA9IGFzLm51bWVyaWMoZGF0ZS1sYWcoZGF0ZSkpKSAlPiUgDQogIG11dGF0ZShuY2hhciA9IG5jaGFyKGV2ZW50KSwgDQogICAgICAgICBuY2hhcl9zY2FsZWQgPSAobmNoYXItbWluKG5jaGFyKSkvKG1heChuY2hhciktbWluKG5jaGFyKSksIA0KICAgICAgICAgIyBwb2ludF9wb3NpdGlvbiA9IDcwMCAqIG5jaGFyX3NjYWxlZCAqICgtMSlecm93aWQsDQogICAgICAgICBwb2ludF9wb3NpdGlvbiA9IGMoNTAsMTAwLDI4MCw0MjAsNTUwLDcyMCwxMDAsNTUwLDcyMCwxNTAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgMjQwLDc4MCw4MzAsMzAwKSooLTEpXnJvd2lkDQogICAgICAgICApICU+JSANCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHF1YXJ0ZXIoZGF0ZSwgd2l0aF95ZWFyID0gVCkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD1kYXRlLCB5PTApKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3BvaW50KGFlcyhjb2w9cmVnaW9uKSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHg9ZGF0ZSwgeGVuZD1kYXRlLCBjb2w9cmVnaW9uLA0KICAgICAgICAgICAgICAgICAgIHk9MCwgeWVuZD1wb2ludF9wb3NpdGlvbikpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1wb2ludF9wb3NpdGlvbiwgY29sPXJlZ2lvbiksIHNoYXBlPTEpICsNCiAgZ2VvbV90ZXh0KGFlcyh5PS0xMCwgDQogICAgICAgICAgICAgICAgbGFiZWw9cGFzdGUwKGRheShkYXRlKSwgIiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9udGgoZGF0ZSwgbGFiZWw9VCkpKSwgDQogICAgICAgICAgICBhbmdsZT0zMCwgDQogICAgICAgICAgICB2anVzdD0xLCBoanVzdD0xKSArIA0KICBnZW9tX2xhYmVsKGFlcyhsYWJlbD1zdHJfd3JhcChwYXN0ZTAoZGF0ZSwgIjogIiwgZXZlbnQpLCBuY2hhci8zKSwgYWxwaGE9LjcsDQogICAgICAgICAgICAgICAgICMgZGlyZWN0aW9ucz0ieSIsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IEluZiwNCiAgICAgICAgICAgICAgICAgeD1kYXRlLCB5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uLCB2anVzdD0ib3V0d2FyZCIpKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgDQogICAgICAgICAgICAgICBkYXRlX2xhYmVscyA9ICIlYiAlWSIpICsgDQogICMgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyLCBzdHJpcC5wb3NpdGlvbj0idG9wIiwNCiAgIyAgICAgICAgICAgIG5jb2wgPSAxLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICAjIGNvb3JkX2ZsaXAoKSArDQogIHlsaW0oLTEyMDAsMTIwMCkgKyANCiAgY29vcmRfY2FydGVzaWFuKGNsaXAgPSAib2ZmIikgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJBVS9OU1cgQ292aWQtMTkgdGltZWxpbmUsIDJuZCBoYWxmIDIwMjAiKSArDQogIHRoZW1lX3ZvaWQoYmFzZV9zaXplID0gMjMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgIyByZWN0ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwNCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMi4zLCAwLCAyLjMpLCJjbSIpLA0KICAgICAgICAjIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTlVMTCkNCiAgICAgICAgKQ0KYGBgDQoNCiMjIEZ1bGwNCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0yNX0NCkFVX3RpbWVsaW5lICU+JSANCiAgIyBmaWx0ZXIoZGF0ZSA+PSB5bWQoMjAyMDAyMjApKSAlPiUgDQogIGFycmFuZ2UoZGF0ZSkgJT4lIA0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDAxMjApLCBldmVudD0iIikgJT4lDQogICMgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwMjIwKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDAzMzEpLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDQwMSksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAwNjMwKSwgZXZlbnQ9IiIpICU+JQ0KICBhZGRfcm93KGRhdGUgPSB5bWQoMjAyMDA3MDEpLCBldmVudD0iIikgJT4lDQogIGFkZF9yb3coZGF0ZSA9IHltZCgyMDIwMDkzMCksIGV2ZW50PSIiKSAlPiUNCiAgYWRkX3JvdyhkYXRlID0geW1kKDIwMjAxMDAxKSwgZXZlbnQ9IiIpICU+JQ0KICAjIGZpbHRlcihuY2hhcihldmVudCkgPCAyMzApICU+JSANCiAgIyBmaWx0ZXIocmVnaW9uICE9ICJWSUMiKSAlPiUgDQogIG11dGF0ZShyb3dpZCA9IGFzLm51bWVyaWMocm93bmFtZXMoLikpKSAlPiUgDQogIG11dGF0ZShkYXRlX2dhcCA9IGFzLm51bWVyaWMoZGF0ZS1sYWcoZGF0ZSkpKSAlPiUgDQogIG11dGF0ZShuY2hhciA9IG5jaGFyKGV2ZW50KSwgDQogICAgICAgICBuY2hhcl9zY2FsZWQgPSAobmNoYXItbWluKG5jaGFyKSkvKG1heChuY2hhciktbWluKG5jaGFyKSksIA0KICAgICAgICAgcG9pbnRfcG9zaXRpb24gPSA4MDAgKiBuY2hhcl9zY2FsZWQgKiAoLTEpXnJvd2lkLA0KICAgICAgICAgIyBwb2ludF9wb3NpdGlvbiA9IGMoMTAwKSooLTEpXnJvd2lkDQogICAgICAgICApICU+JSANCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHF1YXJ0ZXIoZGF0ZSwgd2l0aF95ZWFyID0gVCkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD1kYXRlLCB5PTApKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3BvaW50KGFlcyhjb2w9cmVnaW9uKSkgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHg9ZGF0ZSwgeGVuZD1kYXRlLCBjb2w9cmVnaW9uLA0KICAgICAgICAgICAgICAgICAgIHk9MCwgeWVuZD1wb2ludF9wb3NpdGlvbikpICsNCiAgZ2VvbV9wb2ludChhZXMoeT1wb2ludF9wb3NpdGlvbiwgY29sPXJlZ2lvbiksIHNoYXBlPTEpICsNCiAgZ2VvbV90ZXh0KGFlcyh5PS0xMCwgDQogICAgICAgICAgICAgICAgbGFiZWw9cGFzdGUwKGRheShkYXRlKSwgIiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9udGgoZGF0ZSwgbGFiZWw9VCkpKSwgDQogICAgICAgICAgICBhbmdsZT0zMCwgDQogICAgICAgICAgICB2anVzdD0xLCBoanVzdD0xKSArIA0KICBnZW9tX2xhYmVsKGFlcyhsYWJlbD1zdHJfd3JhcChwYXN0ZTAoZGF0ZSwgIjogIiwgZXZlbnQpLCBuY2hhci8yKSwgYWxwaGE9LjcsDQogICAgICAgICAgICAgICAgICMgZGlyZWN0aW9ucz0ieSIsIG1pbi5zZWdtZW50Lmxlbmd0aCA9IEluZiwNCiAgICAgICAgICAgICAgICAgeD1kYXRlLCB5PXBvaW50X3Bvc2l0aW9uLCBjb2w9cmVnaW9uLCB2anVzdD0ib3V0d2FyZCIpKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICIxIG1vbnRoIiwgDQogICAgICAgICAgICAgICBkYXRlX2xhYmVscyA9ICIlYiAlWSIpICsgDQogIGZhY2V0X3dyYXAofmZhY2V0X3Zhciwgc3RyaXAucG9zaXRpb249InRvcCIsDQogICAgICAgICAgICAgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3giKSArDQogICMgY29vcmRfZmxpcCgpICsNCiAgeWxpbSgtMTIwMCwxMjAwKSArIA0KICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICJvZmYiKSArIA0KICB0aGVtZV92b2lkKGJhc2Vfc2l6ZSA9IDIzKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgICAgICMgcmVjdCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiksDQogICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDIuMywgMCwgMi4zKSwiY20iKSwNCiAgICAgICAgIyBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5VTEwpDQogICAgICAgICkNCmBgYA0KDQojIFRpbWUgc2VyaWVzDQojIyBEYWlseQ0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NH0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGNvdW50KG5vdGlmaWNhdGlvbl9kYXRlKSAlPiUgDQogIGdncGxvdChhZXMoeD1ub3RpZmljYXRpb25fZGF0ZSAsIHk9bikpICsgDQogICMgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fbGluZSgpICsgDQogIHlsYWIoIkNvdW50IG9mIGNhc2VzIikgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJEYWlseSBuZXcgY29uZmlybWVkIENvdmlkLTE5IGNhc2VzIChTWUQpIikgKyANCiAgYW5ub3RhdGUoInRleHQiLCB4PXltZCgyMDIwMDUwNSksIHk9NjAsIHNpemU9My4zLCBjb2w9ImRhcmtyZWQiLCANCiAgICAgICAgICAgbGFiZWw9IjFzdCBvdXRicmVhayBcbiAoQm9uZGkgYmVhY2gsIFxuU291dGggRWFzdGVybiBcblN5ZG5leSwgMjAyNikiKSArIA0KICBhbm5vdGF0ZSgidGV4dCIsIHg9eW1kKDIwMjAwODE1KSwgeT0yNSwgc2l6ZT0zLjMsIGNvbD0iZGFya3JlZCIsIA0KICAgICAgICAgICBsYWJlbD0iMm5kIG91dGJyZWFrIFxuIChXZXN0bWVhZCAmIExpdmVycG9vbCwgXG5XZXN0ZXJuIFN5ZG5leSwgMjE0NSkiKSArIA0KICBhbm5vdGF0ZSgidGV4dCIsIHg9eW1kKDIwMjEwMTAxKSwgeT0zNSwgc2l6ZT0zLjMsIGNvbD0iZGFya3JlZCIsIA0KICAgICAgICAgICBsYWJlbD0iM3JkIG91dGJyZWFrIFxuIChBdmFsb24gYmVhY2gsIE5vcnRoZXJuIFN5ZG5leSwgMjEwNykiKSArIA0KICBnZ2woKQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgY291bnQobGhkXzIwMTBfbmFtZSwgbm90aWZpY2F0aW9uX2RhdGUpICU+JSANCiAgZ2dwbG90KGFlcyh4PW5vdGlmaWNhdGlvbl9kYXRlICwgeT1uLCBjb2w9bGhkXzIwMTBfbmFtZSkpICsgDQogICMgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fbGluZSgpICsgDQogICMgZmFjZXRfd3JhcCh+bGhkXzIwMTBfbmFtZSkgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJEYWlseSBuZXcgY29uZmlybWVkIENvdmlkLTE5IGNhc2VzIChTWUQpIikgKyANCiAgZ2dsKGxwID0gInJpZ2h0IikNCmBgYA0KDQojIyBDdW11bGF0aXZlDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD01fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKGxoZF8yMDEwX25hbWUgPSBpZmVsc2UobGhkXzIwMTBfbmFtZSA9PSAiU3lkbmV5IiwgIlN5ZG5leSAoYXJvdW5kIENCRCkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGhkXzIwMTBfbmFtZSkpICU+JSANCiAgIyBtdXRhdGUobGhkXzIwMTBfbmFtZSA9IGlmZWxzZShpcy5uYShsaGRfMjAxMF9uYW1lKSwgIlVua25vd24iLCBsaGRfMjAxMF9uYW1lKSkgJT4lDQogIGNvdW50KGxoZF8yMDEwX25hbWUsIG5vdGlmaWNhdGlvbl9kYXRlKSAlPiUgDQogIGdyb3VwX2J5KGxoZF8yMDEwX25hbWUpICU+JSANCiAgbXV0YXRlKGRheXNfc2luY2VfZmlyc3RfY2FzZSA9IG5vdGlmaWNhdGlvbl9kYXRlIC0gbWluKG5vdGlmaWNhdGlvbl9kYXRlKSkgJT4lIA0KICBtdXRhdGUoYWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0obikpICU+JSANCiAgbXV0YXRlKGxhYiA9IGlmZWxzZShub3RpZmljYXRpb25fZGF0ZSA9PSBtYXgobm90aWZpY2F0aW9uX2RhdGUsIG5hLnJtPVQpLCANCiAgICAgICAgICAgICAgICAgICAgICBsaGRfMjAxMF9uYW1lLCBOQSkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD1ub3RpZmljYXRpb25fZGF0ZSAsIHk9YWNjdW11bGF0ZWRfY2FzZXMsIGNvbD1saGRfMjAxMF9uYW1lKSkgKyANCiAgIyBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9saW5lKCkgKyANCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbD1sYWIpLCBzaXplPTQsIGhqdXN0PS0uMSwgbWluLnNlZ21lbnQubGVuZ3RoID0gMTApICsgDQogICMgZmFjZXRfd3JhcCh+bGhkXzIwMTBfbmFtZSkgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJBY2N1bXVsYXRlZCBjb25maXJtZWQgQ292aWQtMTkgY2FzZXMgKFNZRCksIGJ5IExvY2FsIEhlYWx0aCBEaXN0cmljdCAoTEhEKSIpICsgDQogICMgeGxpbShjKDAsNTUwKSkgKw0KICBnZ2woYmFzZV9zaXplPTEyLCBscCA9ICJub25lIikgDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTZ9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBtdXRhdGUobGhkXzIwMTBfbmFtZSA9IGlmZWxzZShsaGRfMjAxMF9uYW1lID09ICJTeWRuZXkiLCAiU3lkbmV5IChhcm91bmQgQ0JEKSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaGRfMjAxMF9uYW1lKSkgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICAjIGZpbHRlcihsaGRfMjAxMF9uYW1lICVpbiUgYygiU291dGggRWFzdGVybiBTeWRuZXkiLCANCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIk5vcnRoZXJuIFN5ZG5leSIsIA0KICAjICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VzdGVybiBTeWRuZXkiLCANCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgIlNvdXRoIFdlc3Rlcm4gU3lkbmV5IiwgDQogICMgICAgICAgICAgICAgICAgICAgICAgICAgICJTeWRuZXkiKSB8IGlzLm5hKGxoZF8yMDEwX25hbWUpKSAlPiUgDQogIGNvdW50KGxoZF8yMDEwX25hbWUsIHBvc3Rjb2RlLCBub3RpZmljYXRpb25fZGF0ZSkgJT4lIA0KICBncm91cF9ieShsaGRfMjAxMF9uYW1lLCBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoZGF5c19zaW5jZV9maXJzdF9jYXNlID0gbm90aWZpY2F0aW9uX2RhdGUgLSBtaW4obm90aWZpY2F0aW9uX2RhdGUpKSAlPiUgDQogIG11dGF0ZShhY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShuKSkgJT4lIA0KICBtdXRhdGUobGFiPWlmZWxzZShub3RpZmljYXRpb25fZGF0ZSA9PSBtYXgobm90aWZpY2F0aW9uX2RhdGUpLCBwb3N0Y29kZSwgTkEpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9bm90aWZpY2F0aW9uX2RhdGUgLCB5PWFjY3VtdWxhdGVkX2Nhc2VzLCANCiAgICAgICAgICAgICBncm91cD1wb3N0Y29kZSwNCiAgICAgICAgICAgICBjb2w9bGhkXzIwMTBfbmFtZSkpICsgDQogICMgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fdGV4dChhZXMobGFiZWw9bGFiKSwgc2l6ZT0zLCBoanVzdD0ib3V0d2FyZCIpICsgDQogIGZhY2V0X3dyYXAofmxoZF8yMDEwX25hbWUpICsNCiAgbGFicyhzdWJ0aXRsZSA9ICJBY2N1bXVsYXRlZCBjb25maXJtZWQgQ292aWQtMTkgY2FzZXMgKFNZRCksIGJ5IHBvc3Rjb2RlIChQT0EpIikgKyANCiAgIyB4bGltKGMoMCw1NTApKSArDQogIGdnbChiYXNlX3NpemU9MTIsIGxwID0gIm5vbmUiLCApICsgDQogIHRoZW1lKHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KYGBgDQoNCiMgTWFwDQoNCkxvb2tzIGxpa2UgZWFjaCBwb3N0Y29kZSAoUE9BKSBjYW4gb25seSBiZWxvbmcgdG8gb25lIExHQSwgd2hpY2ggaXMgbm90IHRoZSBjYXNlIGZvciBTQTINCg0KYGBge3J9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBkaXN0aW5jdChwb3N0Y29kZSwgbGdhX25hbWUxOSkgJT4lIA0KICBjb3VudChwb3N0Y29kZSkgJT4lIA0KICBzdW1tYXJpc2UobWF4KG4pKSAlPiUgDQogIHB1bGwoKQ0KYGBgDQoNCg0KIyMgTEdBDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihsZ2FfbmFtZTE5ICVpbiUgU1lEX0xHQSRMR0FfTkFNRTE5KSAlPiUgDQogIGNvdW50KGxnYV9uYW1lMTksIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICByZW5hbWUoTEdBX05BTUUxOSA9IGxnYV9uYW1lMTkpICU+JSANCiAgbXV0YXRlKExHQV9OQU1FMTkgPSBmY3RfcmVvcmRlcihMR0FfTkFNRTE5LCBUb3RhbF9jYXNlcykpICU+JSANCiAgcGxvdF9tYXBfVEwoU1lEX0xHQSwgIkxHQV9OQU1FMTkiLCAiVG90YWxfY2FzZXMiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IExHQSAoU1lEKSIsIHNob3dfY291bnQgPSBUKQ0KYGBgDQoNCiMjIFBPQQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgY291bnQocG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgcGxvdF9tYXBfVEwoU1lEX1BPQSwgIlBPQV9OQU1FMTYiLCAiVG90YWxfY2FzZXMiLCANCiAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEKSIsIA0KICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgbGFiZWxfc2l6ZSA9IDIpDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUNCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JQ0KICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUNCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JQ0KICBtdXRhdGUoY2x1c3Rlcl9vcmlnaW4gPSBpZmVsc2UoUE9BX05BTUUxNiAlaW4lIGMoIjIwMjYiLCAiMjE0NSIsICIyMTA3IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY2x1c3Rlcl9vcmlnaW4iLCAiIikgJT4lIGFzLmZhY3RvcikgJT4lDQogIHBsb3RfbWFwX2ZhY3Rvcl9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsICJjbHVzdGVyX29yaWdpbiIsDQogICAgICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCksIGhpZ2hsaWdodGVkIGJ5IGNsdXN0ZXIgb3JpZ2luIiwNCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyKQ0KYGBgDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoIShwb3N0Y29kZSAlaW4lIGMoMjAyNiwgMjE0NSwgMjE3MCkpKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGNvdW50KHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIlRvdGFsX2Nhc2VzIiwgDQogICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCksIGV4Y2x1ZGluZyB0b3AgMyBQT0EiLCANCiAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyKQ0KYGBgDQoNCiMjIE5vdGUNCg0KTm9ydGhlcm4gQmVhY2hlcyBoYXMgbWFueSBwb3N0Y29kZXMgd2hpY2ggcmVzdWx0IGluIG1vcmUgZGlsdXRlZCBjaG9yb3BsZXRoIGJ5IFBPQS4NCg0KYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBkaXN0aW5jdChsZ2FfbmFtZTE5LCBwb3N0Y29kZSkgJT4lIA0KICBjb3VudChsZ2FfbmFtZTE5LCBuYW1lPSJOdW1iZXJfb2ZfcG9zdGNvZGVzIikgJT4lIA0KICBsZWZ0X2pvaW4oY29uZmlybWVkX2Nhc2VzICU+JSBjb3VudChsZ2FfbmFtZTE5LCBuYW1lPSJUb3RhbF9jYXNlcyIpLCANCiAgICAgICAgICAgIGJ5PSJsZ2FfbmFtZTE5IikgJT4lIA0KICBzbGljZV9tYXgobj0zMCwgb3JkZXJfYnkgPSBUb3RhbF9jYXNlcykgJT4lIA0KICBnYXRoZXIoa2V5LCB2YWx1ZSwgLWxnYV9uYW1lMTkpICU+JSANCiAgZ2dwbG90KGFlcyh4PXJlb3JkZXIobGdhX25hbWUxOSwgdmFsdWUpLCB5PXZhbHVlKSkgKyANCiAgZ2VvbV9jb2woKSArIA0KICBmYWNldF93cmFwKH5rZXksIHNjYWxlcyA9ICJmcmVlX3giKSArIA0KICBjb29yZF9mbGlwKCkgKyANCiAgeGxhYigiIikgKyB5bGFiKCIiKSArIA0KICBnZ2woKQ0KYGBgDQoNCiMgTWFwIG92ZXJ0aW1lIGN1bXVsYXRpdmUNCiMjIEJ5IHF1YXJ0ZXIgey50YWJzZXR9DQojIyMgQWNjdW11bGF0ZWQgY2FzZXMNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZSh5ZWFyX3F1YXJ0ZXIgPSBwYXN0ZSh5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSwgIlEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWFydGVyKG5vdGlmaWNhdGlvbl9kYXRlKSwgc2VwPSItIikpICU+JSANCiAgY291bnQoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKHllYXJfcXVhcnRlciwgcG9zdGNvZGUsIGZpbGwgPSBsaXN0KFRvdGFsX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShUb3RhbF9jYXNlcykpICU+JSANCiAgZ3JvdXBfYnkoeWVhcl9xdWFydGVyKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpKSkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcGFzdGUwKHllYXJfcXVhcnRlciwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuQWNjdW11bGF0ZWQ6ICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hKHN1bShBY2N1bXVsYXRlZF9jYXNlcykpKSkgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIA0KICBwbG90X21hcF9UTChybWFwc2hhcGVyOjptc19zaW1wbGlmeSgNCiAgICBTWURfUE9BW1NZRF9QT0EkUE9BX05BTUUxNiAlaW4lIGFzLmNoYXJhY3RlcigNCiAgICAgIGNvbmZpcm1lZF9jYXNlcyRwb3N0Y29kZSkgLF0sIC4wMSksIA0KICAgICAgICAgICAgICAiUE9BX05BTUUxNiIsICJBY2N1bXVsYXRlZF9jYXNlcyIsIA0KICAgICAgICAgICAiVG90YWwgYWNjdW11bGF0ZWQgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQpLCBieSBxdWFydGVyIiwgDQogICAgICAgICAgIHJldHVybl9vYmo9Im1hcCIpICsgDQogIGZhY2V0X3dyYXAofmZhY2V0X3ZhcikgKyANCiAgdGhlbWVfbWFwX2ZhY2V0X1RMICsgDQogIHRoZW1lKCkNCmBgYA0KDQojIyMgQWNjdW11bGF0ZWQgc2hhcmUNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZSh5ZWFyX3F1YXJ0ZXIgPSBwYXN0ZSh5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSwgIlEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWFydGVyKG5vdGlmaWNhdGlvbl9kYXRlKSwgc2VwPSItIikpICU+JSANCiAgY291bnQoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKHllYXJfcXVhcnRlciwgcG9zdGNvZGUsIGZpbGwgPSBsaXN0KFRvdGFsX2Nhc2VzPTApKSAlPiUgDQogIGdyb3VwX2J5KHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9jYXNlcyA9IGN1bXN1bShUb3RhbF9jYXNlcykpICU+JSANCiAgZ3JvdXBfYnkoeWVhcl9xdWFydGVyKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpKSkgJT4lDQogIG11dGF0ZShmYWNldF92YXIgPSBwYXN0ZTAoeWVhcl9xdWFydGVyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgDQogIHBsb3RfbWFwX1RMKHJtYXBzaGFwZXI6Om1zX3NpbXBsaWZ5KA0KICAgIFNZRF9QT0FbU1lEX1BPQSRQT0FfTkFNRTE2ICVpbiUgYXMuY2hhcmFjdGVyKA0KICAgICAgY29uZmlybWVkX2Nhc2VzJHBvc3Rjb2RlKSAsXSwgLjAxKSwgDQogICAgICAgICAgICAgICJQT0FfTkFNRTE2IiwgIkFjY3VtdWxhdGVkX3NoYXJlIiwgDQogICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCkiLCANCiAgICAgICAgICAgcmV0dXJuX29iaj0ibWFwIikgKyANCiAgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyKSArIA0KICB0aGVtZV9tYXBfZmFjZXRfVEwNCmBgYA0KDQojIyBCeSB3ZWVrIE1hci1NYXkgMjAyMCB7LnRhYnNldH0NCiMjIyBBY2N1bXVsYXRlZCBjYXNlcw0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD0xMH0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGZpbHRlcih5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSA9PSAyMDIwLCANCiAgICAgICAgICMgbW9udGgobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMzo1LCANCiAgICAgICAgIGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMTA6MjMpICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKGlzb3dlZWsgPSBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSkgJT4lIA0KICBjb3VudChpc293ZWVrLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKGlzb3dlZWssIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KGlzb3dlZWspICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCgid2VlayAiLCBpc293ZWVrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGlzb3dlZWspKSAlPiUgDQogIA0KICBwbG90X21hcF9UTChybWFwc2hhcGVyOjptc19zaW1wbGlmeShTWURfUE9BLCAuMDEpLCANCiAgICAgICAgICAgICAgIlBPQV9OQU1FMTYiLCAiQWNjdW11bGF0ZWRfY2FzZXMiLCANCiAgICAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEKSIsIA0KICAgICAgICAgICAgICByZXR1cm5fb2JqPSJtYXAiKSArIA0KICBmYWNldF93cmFwKH5mYWNldF92YXIpICsgDQogIHRoZW1lX21hcF9mYWNldF9UTCArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjgzLCAuMTUpKQ0KYGBgDQoNCiMjIyBBY2N1bXVsYXRlZCBzaGFyZQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD0xMH0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGZpbHRlcih5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSA9PSAyMDIwLCANCiAgICAgICAgICMgbW9udGgobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMzo1LCANCiAgICAgICAgIGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMTA6MjMpICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKGlzb3dlZWsgPSBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSkgJT4lIA0KICBjb3VudChpc293ZWVrLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKGlzb3dlZWssIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KGlzb3dlZWspICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgbmEucm09VCkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBtdXRhdGUoZmFjZXRfdmFyID0gcGFzdGUwKCJ3ZWVrICIsIGlzb3dlZWssIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJcbkFjY3VtdWxhdGVkOiAiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21tYShzdW0oQWNjdW11bGF0ZWRfY2FzZXMpKSkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZmlsdGVyKCFpcy5uYShpc293ZWVrKSkgJT4lIA0KICANCiAgcGxvdF9tYXBfVEwocm1hcHNoYXBlcjo6bXNfc2ltcGxpZnkoU1lEX1BPQSwgLjAxKSwgDQogICAgICAgICAgICAgICJQT0FfTkFNRTE2IiwgIkFjY3VtdWxhdGVkX3NoYXJlIiwgDQogICAgICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCkiLCANCiAgICAgICAgICAgICAgcmV0dXJuX29iaj0ibWFwIikgKyANCiAgZmFjZXRfd3JhcCh+ZmFjZXRfdmFyKSArIA0KICB0aGVtZV9tYXBfZmFjZXRfVEwgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC44MywgLjE1KSkNCmBgYA0KDQojIERpc3RyaWJ1dGlvbiBvZiBzaGFyZSBvdmVydGltZQ0KIyMgQnkgcXVhcnRlcg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9My4zfQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgY29tcGxldGUoeWVhcl9xdWFydGVyLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlKSAlPiUgDQogIHJlcGxhY2VfbmEobGlzdChBY2N1bXVsYXRlZF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgbmEucm09VCkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD15ZWFyX3F1YXJ0ZXIsIHk9QWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGZpbGw9QWNjdW11bGF0ZWRfY2FzZXMgPiA1MCwNCiAgICAgICAgICAgICBncm91cD1hcy5mYWN0b3IoUE9BX05BTUUxNikpKSArIA0KICBnZW9tX2NvbChjb2w9IndoaXRlIiwgc2l6ZT0uMSkgKyANCiAgZ2dmKGZjID0gRENbMjoxXSkgKyANCiAgZ2dsKCJ0b3AiLCBsdCA9IFQpDQpgYGANCg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Mi41fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKHllYXJfcXVhcnRlciA9IHBhc3RlKHllYXIobm90aWZpY2F0aW9uX2RhdGUpLCAiUSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1YXJ0ZXIobm90aWZpY2F0aW9uX2RhdGUpLCBzZXA9Ii0iKSkgJT4lIA0KICBjb3VudCh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBjb21wbGV0ZSh5ZWFyX3F1YXJ0ZXIsIHBvc3Rjb2RlKSAlPiUgDQogIHJlcGxhY2VfbmEobGlzdChBY2N1bXVsYXRlZF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieSh5ZWFyX3F1YXJ0ZXIpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgbmEucm09VCkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgDQogIGdncGxvdChhZXMoeD1BY2N1bXVsYXRlZF9zaGFyZSwgZmlsbD1hcy5mYWN0b3IoeWVhcl9xdWFydGVyKSkpICsgDQogICMgZ2VvbV9kZW5zaXR5KCkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oKSArIA0KICBmYWNldF93cmFwKH55ZWFyX3F1YXJ0ZXIsIG5yb3cgPSAxKSArIA0KICB4bGltKDAsLjAzKSArIA0KICB5bGltKDAsNDApICsNCiAgZ2dsKCJub25lIikNCmBgYA0KDQojIyBCeSB3ZWVrDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zLjN9DQpjb25maXJtZWRfY2FzZXMgJT4lIA0KICBmaWx0ZXIoYXMuY2hhcmFjdGVyKHBvc3Rjb2RlKSAlaW4lIFNZRF9QT0EkUE9BX05BTUUxNikgJT4lIA0KICBmaWx0ZXIoeWVhcihub3RpZmljYXRpb25fZGF0ZSkgPT0gMjAyMCwgDQogICAgICAgICAjIG1vbnRoKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDM6NSwgDQogICAgICAgICBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSAlaW4lIDEwOjIzKSAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIG11dGF0ZShpc293ZWVrID0gaXNvd2Vlayhub3RpZmljYXRpb25fZGF0ZSkpICU+JSANCiAgY291bnQoaXNvd2VlaywgcG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICBjb21wbGV0ZShpc293ZWVrLCBwb3N0Y29kZSwgZmlsbCA9IGxpc3QoVG90YWxfY2FzZXM9MCkpICU+JSANCiAgZ3JvdXBfYnkocG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX2Nhc2VzID0gY3Vtc3VtKFRvdGFsX2Nhc2VzKSkgJT4lIA0KICBncm91cF9ieShpc293ZWVrKSAlPiUgDQogIG11dGF0ZShBY2N1bXVsYXRlZF9zaGFyZSA9IChBY2N1bXVsYXRlZF9jYXNlcy9zdW0oQWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpKSkgJT4lDQogIG11dGF0ZShmYWNldF92YXIgPSBwYXN0ZTAoIndlZWsgIiwgaXNvd2VlaywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlxuQWNjdW11bGF0ZWQ6ICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbW1hKHN1bShBY2N1bXVsYXRlZF9jYXNlcykpKSkgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZmlsdGVyKCFpcy5uYShpc293ZWVrKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4PWlzb3dlZWssIHk9QWNjdW11bGF0ZWRfY2FzZXMsIA0KICAgICAgICAgICAgIGZpbGw9QWNjdW11bGF0ZWRfY2FzZXMgPiAyMCwNCiAgICAgICAgICAgICBncm91cD1hcy5mYWN0b3IoUE9BX05BTUUxNikpKSArIA0KICBnZW9tX2NvbChjb2w9IndoaXRlIiwgc2l6ZT0uMSkgKyANCiAgZ2d4KHJvdW5kLCBwYm49MTIpICsNCiAgZ2dmKGZjID0gRENbMjoxXSkgKyANCiAgZ2dsKCJ0b3AiLCBsdCA9IFQpDQpgYGANCg0KDQpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NX0NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGZpbHRlcih5ZWFyKG5vdGlmaWNhdGlvbl9kYXRlKSA9PSAyMDIwLCANCiAgICAgICAgICMgbW9udGgobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMzo1LCANCiAgICAgICAgIGlzb3dlZWsobm90aWZpY2F0aW9uX2RhdGUpICVpbiUgMTA6MjMpICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgbXV0YXRlKGlzb3dlZWsgPSBpc293ZWVrKG5vdGlmaWNhdGlvbl9kYXRlKSkgJT4lIA0KICBjb3VudChpc293ZWVrLCBwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogIGNvbXBsZXRlKGlzb3dlZWssIHBvc3Rjb2RlLCBmaWxsID0gbGlzdChUb3RhbF9jYXNlcz0wKSkgJT4lIA0KICBncm91cF9ieShwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoQWNjdW11bGF0ZWRfY2FzZXMgPSBjdW1zdW0oVG90YWxfY2FzZXMpKSAlPiUgDQogIGdyb3VwX2J5KGlzb3dlZWspICU+JSANCiAgbXV0YXRlKEFjY3VtdWxhdGVkX3NoYXJlID0gKEFjY3VtdWxhdGVkX2Nhc2VzL3N1bShBY2N1bXVsYXRlZF9jYXNlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCkpKSAlPiUNCiAgbXV0YXRlKGZhY2V0X3ZhciA9IHBhc3RlMCgid2VlayAiLCBpc293ZWVrLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiXG5BY2N1bXVsYXRlZDogIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWEoc3VtKEFjY3VtdWxhdGVkX2Nhc2VzKSkpKSAlPiUgDQogIHJlbmFtZShQT0FfTkFNRTE2ID0gcG9zdGNvZGUpICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihhcy5mYWN0b3IoUE9BX05BTUUxNiksIFRvdGFsX2Nhc2VzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGlzb3dlZWspKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHg9QWNjdW11bGF0ZWRfc2hhcmUsIGZpbGw9YXMuZmFjdG9yKGlzb3dlZWspKSkgKyANCiAgIyBnZW9tX2RlbnNpdHkoKSArIA0KICBnZW9tX2hpc3RvZ3JhbSgpICsgDQogIGZhY2V0X3dyYXAofmlzb3dlZWssIG5yb3cgPSAzLCBsYWJlbGxlciA9ICJsYWJlbF9ib3RoIikgKyANCiAgeGxpbSgwLC4wMykgKyANCiAgeWxpbSgwLDQwKSArDQogIGdnbCgibm9uZSIpDQpgYGANCg0KIyBMb2NhbCBQT0kNCiMjIFB1YmxpYyB0cmFuc3BvcnQNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogICAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgICBjb3VudChwb3N0Y29kZSwgbmFtZT0iVG90YWxfY2FzZXMiKSAlPiUgDQogICAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICAgIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJUb3RhbF9jYXNlcyIsIGZpbGxfY29sID0gImdyZXkzMyIsDQogICAgICAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEKSwgd2l0aCBwdWJsaWMgdHJhbnNwb3J0IiwgDQogICAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyLCByZXR1cm5fb2JqID0gIm1hcCIpICsNCiAgDQogICMgZ2VvbV9tYXAoaW5oZXJpdC5hZXMgPSBGQUxTRSwgYWxwaGE9Ljg1LA0KICAjICAgICAgICAgIGFlcyhtYXBfaWQgPSBpZCksIG1hcCA9IHRpZHkoU1lEX1BPQSksIA0KICAjICAgICAgICAgIGNvbD0iZ3JleTUwIiwgc2l6ZT0uMywgZmlsbD0id2hpdGUiKSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX3RyYWlucywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9IlRyYWluIiwNCiAgICAgICAgICAgICAgICBncm91cCA9IGBSYWlsd2F5IGxpbmUocylgKSwNCiAgICAgICAgICAgIHNpemU9LjgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfZmVycmllcywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9IkZlcnJ5IiksDQogICAgICAgICAgICAgc2l6ZT0uOCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF9saWdodHJhaWxzLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iTGlnaHRyYWlsIiksDQogICAgICAgICAgICAgc2l6ZT0uOCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF9tZXRybywgDQogICAgICAgICAgICBhZXMoeD1sb24sIHk9bGF0LCBjb2w9Ik1ldHJvIiksDQogICAgICAgICAgICAgc2l6ZT0uOCkgKw0KICBnZ2MoYygiZGVlcHNreWJsdWUiLCAicmVkIiwgImRhcmtncmVlbiIsICJvcmFuZ2UiKSkgKyANCiAgZ3VpZGVzKGNvbD1ndWlkZV9sZWdlbmQodGl0bGU9IlRyYW5zcG9ydF9tb2RlIikpICsgDQogIGV4cGFuZF9saW1pdHMoeCA9IHRpZHkoU1lEX1BPQSkkbG9uZywgeSA9IHRpZHkoU1lEX1BPQSkkbGF0KSArDQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygxNTAuNywgMTUxLjQ4KSwgeWxpbSA9IGMoLTM0LjEsIC0zMy41KSkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC45LC4zNSkpDQpgYGANCg0KDQojIyBIb3NwaXRhbHMsIFNjaG9vbHMsIFN1cGVybWFya2V0DQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTh9DQpiaW5kX3Jvd3MoDQogIFNZRF9zaG9wcyAlPiUgc2VsZWN0KGxvbiwgbGF0KSAlPiUgDQogICAgcmVuYW1lKExvbmcgPSBsb24sIExhdCA9IGxhdCkgJT4lIG11dGF0ZShvYmogPSAiU2hvcHBpbmcgY2VudHJlcyIpLCANCiAgU1lEX3N1cGVybWFya2V0cyAlPiUgc2VsZWN0KGxvbiwgbGF0KSAlPiUgDQogICAgcmVuYW1lKExvbmcgPSBsb24sIExhdCA9IGxhdCkgJT4lIG11dGF0ZShvYmogPSAiU3VwZXJtYXJrZXRzIiksIA0KICBTWURfaG9zcGl0YWxzICU+JSBzZWxlY3QoTG9uZ2l0dWRlLCBMYXRpdHVkZSkgJT4lIA0KICAgIHJlbmFtZShMb25nID0gTG9uZ2l0dWRlLCBMYXQgPSBMYXRpdHVkZSkgJT4lIG11dGF0ZShvYmogPSAiSG9zcGl0YWxzIiksIA0KICByYmluZChTWURfc3NjaG9vbHMgJT4lIHNlbGVjdChMb25nLCBMYXQpLA0KICAgICAgICBTWURfcHNjaG9vbHMgJT4lIHNlbGVjdChMb25nLCBMYXQpKSAlPiUgbXV0YXRlKG9iaiA9ICJTY2hvb2xzIikNCikgJT4lIA0KICBnZ3Bsb3QoKSArICANCiAgZ2VvbV9tYXAoZGF0YSA9IFNZRF9QT0EsIGluaGVyaXQuYWVzID0gRkFMU0UsIGFscGhhPS44NSwNCiAgICAgICAgICAgYWVzKG1hcF9pZCA9IGlkKSwgbWFwID0gdGlkeShTWURfUE9BKSwgDQogICAgICAgICAgIGNvbD0iZ3JleTUwIiwgc2l6ZT0uMiwgZmlsbD0id2hpdGUiKSArDQogIGdlb21faml0dGVyKGFlcyh4PUxvbmcsIHk9TGF0LCBjb2w9b2JqKSwgc2l6ZT0uOCwgYWxwaGE9LjUpICsgDQogIHN0YXRfZGVuc2l0eTJkKGFlcyh4PUxvbmcsIHk9TGF0LCANCiAgICAgICAgICAgICAgICAgICAgIGZpbGw9Li5sZXZlbC4uLCBhbHBoYT0uLmxldmVsLi4sIGNvbD1vYmopLA0KICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IDEuMiwgZ2VvbT0icG9seWdvbiIsIHNpemU9LjIzKSArIA0KICBmYWNldF93cmFwKH5vYmopICsNCiAgZXhwYW5kX2xpbWl0cyh4ID0gdGlkeShTWURfUE9BKSRsb25nLCB5ID0gdGlkeShTWURfUE9BKSRsYXQpICsNCiAgeGxpbSgxNTAuNywxNTEuNDgpICsgeWxpbSgtMzQuMSwtMzMuNSkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0id2hpdGUiLCBoaWdoPURDWzddKSArIA0KICBzY2FsZV9hbHBoYV9jb250aW51b3VzKHJhbmdlID0gYygwLC4zKSkgKyANCiAgZ2djKGZjID0gYygiZGFya3JlZCIsICJkZWVwc2t5Ymx1ZSIsICJkYXJrYmx1ZSIsICJkYXJrZ3JlZW4iKSkgKyANCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTE1KSkNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KY29uZmlybWVkX2Nhc2VzICU+JSANCiAgZmlsdGVyKGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkgJWluJSBTWURfUE9BJFBPQV9OQU1FMTYpICU+JSANCiAgY291bnQocG9zdGNvZGUsIG5hbWU9IlRvdGFsX2Nhc2VzIikgJT4lIA0KICByZW5hbWUoUE9BX05BTUUxNiA9IHBvc3Rjb2RlKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCBUb3RhbF9jYXNlcykpICU+JSANCiAgcGxvdF9tYXBfVEwoU1lEX1BPQSwgIlBPQV9OQU1FMTYiLCAiVG90YWxfY2FzZXMiLCBmaWxsX2NvbCA9ICJncmV5MzMiLA0KICAgICAgICAgICAgICAiVG90YWwgQ292aWQtMTkgY2FzZXMgYnkgUE9BIChTWUQpLCBvdmVybGF5ZWQgd2l0aCBob3NwaXRhbHMsIHNjaG9vbHMsIHNob3BwaW5nIGNlbnRyZXMgJiBzdXBlcm1hcmtldHMiLCANCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyLCByZXR1cm5fb2JqID0gIm1hcCIpICsNCiAgDQogICMgZ2VvbV9tYXAoZGF0YSA9IFNZRF9QT0EsIGluaGVyaXQuYWVzID0gRkFMU0UsIGFscGhhPS44NSwNCiAgIyAgICAgICAgICBhZXMobWFwX2lkID0gaWQpLCBtYXAgPSB0aWR5KFNZRF9QT0EpLCANCiAgIyAgICAgICAgICBjb2w9ImdyZXk1MCIsIHNpemU9LjMsIGZpbGw9IndoaXRlIikgKw0KICBnZW9tX2ppdHRlcihkYXRhID0gYmluZF9yb3dzKA0KICAgIFNZRF9zaG9wcyAlPiUgc2VsZWN0KGxvbiwgbGF0KSAlPiUgDQogICAgICByZW5hbWUoTG9uZyA9IGxvbiwgTGF0ID0gbGF0KSAlPiUgbXV0YXRlKG9iaiA9ICJTaG9wcGluZyBjZW50cmVzIiksIA0KICAgIFNZRF9zdXBlcm1hcmtldHMgJT4lIHNlbGVjdChsb24sIGxhdCkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBsb24sIExhdCA9IGxhdCkgJT4lIG11dGF0ZShvYmogPSAiU3VwZXJtYXJrZXRzIiksIA0KICAgIFNZRF9ob3NwaXRhbHMgJT4lIHNlbGVjdChMb25naXR1ZGUsIExhdGl0dWRlKSAlPiUgDQogICAgICByZW5hbWUoTG9uZyA9IExvbmdpdHVkZSwgTGF0ID0gTGF0aXR1ZGUpICU+JSBtdXRhdGUob2JqID0gIkhvc3BpdGFscyIpLCANCiAgICByYmluZChTWURfc3NjaG9vbHMgJT4lIHNlbGVjdChMb25nLCBMYXQpLA0KICAgICAgICAgIFNZRF9wc2Nob29scyAlPiUgc2VsZWN0KExvbmcsIExhdCkpICU+JSBtdXRhdGUob2JqID0gIlNjaG9vbHMiKQ0KICApLCANCiAgc2l6ZSA9IDEsIGFscGhhID0gLjMsIGFlcyh4PUxvbmcsIHk9TGF0LGNvbD1vYmopKSArDQogIGV4cGFuZF9saW1pdHMoeCA9IHRpZHkoU1lEX1BPQSkkbG9uZywgeSA9IHRpZHkoU1lEX1BPQSkkbGF0KSArDQogIHhsaW0oMTUwLjcsMTUxLjQ4KSArIHlsaW0oLTM0LjEsLTMzLjUpICsNCiAgIyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0id2hpdGUiLCBoaWdoPURDWzddKSArIA0KICBzY2FsZV9hbHBoYV9jb250aW51b3VzKHJhbmdlID0gYygwLC4zKSkgKyANCiAgZ2djKGZjID0gYygiZGFya3JlZCIsICJkYXJrYmx1ZSIsICJkYXJrb3JhbmdlIiwgImRhcmtncmVlbiIpKSArIA0KICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTMpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlPSJQT0kiKSkgKyANCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYyguOSwuMjUpLCANCiAgICAgICAgIyBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpKQ0KYGBgDQojIyBQT0kgY29tYmluZWQNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGNvdW50KHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIlRvdGFsX2Nhc2VzIiwgZmlsbF9jb2wgPSAiZ3JleTMzIiwNCiAgICAgICAgICAgICAgIlRvdGFsIENvdmlkLTE5IGNhc2VzIGJ5IFBPQSAoU1lEKSwgd2l0aCBob3NwaXRhbHMsIHNjaG9vbHMgJiBzdXBlcm1hcmtldHMiLCANCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyLCByZXR1cm5fb2JqID0gIm1hcCIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBTWURfdHJhaW5zLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iVHJhaW4iLA0KICAgICAgICAgICAgICAgIGdyb3VwID0gYFJhaWx3YXkgbGluZShzKWApLA0KICAgICAgICAgICAgc2l6ZT0uOCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IFNZRF9mZXJyaWVzLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iRmVycnkiKSwNCiAgICAgICAgICAgICBzaXplPS44KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX2xpZ2h0cmFpbHMsIA0KICAgICAgICAgICAgYWVzKHg9bG9uLCB5PWxhdCwgY29sPSJMaWdodHJhaWwiKSwNCiAgICAgICAgICAgICBzaXplPS44KSArDQogIGdlb21fbGluZShkYXRhID0gU1lEX21ldHJvLCANCiAgICAgICAgICAgIGFlcyh4PWxvbiwgeT1sYXQsIGNvbD0iTWV0cm8iKSwNCiAgICAgICAgICAgICBzaXplPS44KSArDQogIA0KICAjIGdlb21fbWFwKGRhdGEgPSBTWURfUE9BLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBhbHBoYT0uODUsDQogICMgICAgICAgICAgYWVzKG1hcF9pZCA9IGlkKSwgbWFwID0gdGlkeShTWURfUE9BKSwgDQogICMgICAgICAgICAgY29sPSJncmV5NTAiLCBzaXplPS4zLCBmaWxsPSJ3aGl0ZSIpICsNCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGJpbmRfcm93cygNCiAgICBTWURfc2hvcHMgJT4lIHNlbGVjdChsb24sIGxhdCkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBsb24sIExhdCA9IGxhdCkgJT4lIG11dGF0ZShvYmogPSAiU2hvcHBpbmcgY2VudHJlcyIpLCANCiAgICBTWURfc3VwZXJtYXJrZXRzICU+JSBzZWxlY3QobG9uLCBsYXQpICU+JSANCiAgICAgIHJlbmFtZShMb25nID0gbG9uLCBMYXQgPSBsYXQpICU+JSBtdXRhdGUob2JqID0gIlN1cGVybWFya2V0cyIpLCANCiAgICBTWURfaG9zcGl0YWxzICU+JSBzZWxlY3QoTG9uZ2l0dWRlLCBMYXRpdHVkZSkgJT4lIA0KICAgICAgcmVuYW1lKExvbmcgPSBMb25naXR1ZGUsIExhdCA9IExhdGl0dWRlKSAlPiUgbXV0YXRlKG9iaiA9ICJIb3NwaXRhbHMiKSwgDQogICAgcmJpbmQoU1lEX3NzY2hvb2xzICU+JSBzZWxlY3QoTG9uZywgTGF0KSwNCiAgICAgICAgICBTWURfcHNjaG9vbHMgJT4lIHNlbGVjdChMb25nLCBMYXQpKSAlPiUgbXV0YXRlKG9iaiA9ICJTY2hvb2xzIikNCiAgKSwgDQogIHNpemUgPSAxLCBhbHBoYSA9IC4zLCBhZXMoeD1Mb25nLCB5PUxhdCxjb2w9b2JqKSkgKw0KICBleHBhbmRfbGltaXRzKHggPSB0aWR5KFNZRF9QT0EpJGxvbmcsIHkgPSB0aWR5KFNZRF9QT0EpJGxhdCkgKw0KICB4bGltKDE1MC43LDE1MS40OCkgKyB5bGltKC0zNC4xLC0zMy41KSArDQogICMgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IndoaXRlIiwgaGlnaD1EQ1s3XSkgKyANCiAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZSA9IGMoMCwuMykpICsgDQogIGdnYyhmYyA9IGMoImRlZXBza3libHVlIiwgImRhcmtibHVlIiwgInJlZCIsICJkYXJrZ3JlZW4iLCANCiAgICAgICAgICAgICAiZGFya2JsdWUiLCAicmVkIiwgImRhcmtncmVlbiIsICJvcmFuZ2UiKSkgKyANCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT0zKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZT0iUE9JIikpICsgDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLjksLjQpLCANCiAgICAgICAgIyBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTUpKQ0KYGBgDQoNCiMjIFBPSSBjb3VudCBRQSB7LnRhYnNldH0NCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9MTJ9DQpncmlkLmFycmFuZ2UoDQpuX3BvaV9ieV9QT0EgJT4lIA0KICBmaWx0ZXIoUE9BX05BTUUxNiAhPSAiVW5rbm93biIpICU+JSANCiAgIyBnYXRoZXIoa2V5LCB2YWx1ZSwgLVBPQV9OQU1FMTYpICU+JSANCiAgc2VsZWN0KFBPQV9OQU1FMTYsIG5faG9zcGl0YWxzKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoUE9BX05BTUUxNiwgbl9ob3NwaXRhbHMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIm5faG9zcGl0YWxzIiwgDQogICAgICAgICAgICAgICJOdW1iZXIgb2YgaG9zcGl0YWxzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGFya3JlZCIsIA0KICAgICAgICAgICAgICByZXR1cm5fb2JqID0gIm1hcCIpLCANCm5fcG9pX2J5X1BPQSAlPiUgDQogIGZpbHRlcihQT0FfTkFNRTE2ICE9ICJVbmtub3duIikgJT4lIA0KICAjIGdhdGhlcihrZXksIHZhbHVlLCAtUE9BX05BTUUxNikgJT4lIA0KICBzZWxlY3QoUE9BX05BTUUxNiwgbl9zY2hvb2xzKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoUE9BX05BTUUxNiwgbl9zY2hvb2xzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3NjaG9vbHMiLCANCiAgICAgICAgICAgICAgIk51bWJlciBvZiBzY2hvb2xzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGVlcHNreWJsdWUiLCANCiAgICAgICAgICAgICAgcmV0dXJuX29iaiA9ICJtYXAiKSwgDQpuX3BvaV9ieV9QT0EgJT4lIA0KICBmaWx0ZXIoUE9BX05BTUUxNiAhPSAiVW5rbm93biIpICU+JSANCiAgIyBnYXRoZXIoa2V5LCB2YWx1ZSwgLVBPQV9OQU1FMTYpICU+JSANCiAgc2VsZWN0KFBPQV9OQU1FMTYsIG5fc3VwZXJtYXJrZXRzKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoUE9BX05BTUUxNiwgbl9zdXBlcm1hcmtldHMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIm5fc3VwZXJtYXJrZXRzIiwgDQogICAgICAgICAgICAgICJOdW1iZXIgb2Ygc3VwZXJtYXJrZXRzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGFya2dyZWVuIiwgDQogICAgICAgICAgICAgIHJldHVybl9vYmogPSAibWFwIiksIA0Kbl9wb2lfYnlfUE9BICU+JSANCiAgZmlsdGVyKFBPQV9OQU1FMTYgIT0gIlVua25vd24iKSAlPiUgDQogICMgZ2F0aGVyKGtleSwgdmFsdWUsIC1QT0FfTkFNRTE2KSAlPiUgDQogIHNlbGVjdChQT0FfTkFNRTE2LCBuX3Nob3BwaW5nQ2VudHJlcykgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKFBPQV9OQU1FMTYsIG5fc2hvcHBpbmdDZW50cmVzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3Nob3BwaW5nQ2VudHJlcyIsIA0KICAgICAgICAgICAgICAiTnVtYmVyIG9mIHNob3BwaW5nIGNlbnRyZXMgYnkgUE9BIiwgDQogICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBmaWxsX2NvbCA9ICJibGFjayIsIA0KICAgICAgICAgICAgICByZXR1cm5fb2JqID0gIm1hcCIpLCANCm5fcG9pX2J5X1BPQSAlPiUgDQogIGZpbHRlcihQT0FfTkFNRTE2ICE9ICJVbmtub3duIikgJT4lIA0KICAjIGdhdGhlcihrZXksIHZhbHVlLCAtUE9BX05BTUUxNikgJT4lIA0KICBzZWxlY3QoUE9BX05BTUUxNiwgbl9wdWJsaWNUcmFuc3BvcnRzICkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKFBPQV9OQU1FMTYsIG5fcHVibGljVHJhbnNwb3J0cyApKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIm5fcHVibGljVHJhbnNwb3J0cyIsIA0KICAgICAgICAgICAgICAiTnVtYmVyIG9mIHB1YmxpYyB0cmFuc3BvcnRzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGFya29yYW5nZSIsIA0KICAgICAgICAgICAgICByZXR1cm5fb2JqID0gIm1hcCIpLCANCmNvbmZpcm1lZF9jYXNlcyAlPiUgDQogIGZpbHRlcihhcy5jaGFyYWN0ZXIocG9zdGNvZGUpICVpbiUgU1lEX1BPQSRQT0FfTkFNRTE2KSAlPiUgDQogIGNvdW50KHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgcmVuYW1lKFBPQV9OQU1FMTYgPSBwb3N0Y29kZSkgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKGFzLmZhY3RvcihQT0FfTkFNRTE2KSwgVG90YWxfY2FzZXMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIlRvdGFsX2Nhc2VzIiwgDQogICAgICAgICAgICJUb3RhbCBDb3ZpZC0xOSBjYXNlcyBieSBQT0EgKFNZRCkiLCANCiAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGxhYmVsX3NpemUgPSAyLCANCiAgICAgICAgICAgICAgcmV0dXJuX29iaiA9ICJtYXAiKSwgDQpuY29sPTIpDQpgYGANCg0KIyMjIEhvc3BpdGFsDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpuX3BvaV9ieV9QT0EgJT4lIA0KICBmaWx0ZXIoUE9BX05BTUUxNiAhPSAiVW5rbm93biIpICU+JSANCiAgIyBnYXRoZXIoa2V5LCB2YWx1ZSwgLVBPQV9OQU1FMTYpICU+JSANCiAgc2VsZWN0KFBPQV9OQU1FMTYsIG5faG9zcGl0YWxzKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoUE9BX05BTUUxNiwgbl9ob3NwaXRhbHMpKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgIm5faG9zcGl0YWxzIiwgDQogICAgICAgICAgICAgICJOdW1iZXIgb2YgaG9zcGl0YWxzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGFya3JlZCIpDQpgYGANCg0KIyMjIFNjaG9vbHMNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCm5fcG9pX2J5X1BPQSAlPiUgDQogIGZpbHRlcihQT0FfTkFNRTE2ICE9ICJVbmtub3duIikgJT4lIA0KICAjIGdhdGhlcihrZXksIHZhbHVlLCAtUE9BX05BTUUxNikgJT4lIA0KICBzZWxlY3QoUE9BX05BTUUxNiwgbl9zY2hvb2xzKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoUE9BX05BTUUxNiwgbl9zY2hvb2xzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3NjaG9vbHMiLCANCiAgICAgICAgICAgICAgIk51bWJlciBvZiBzY2hvb2xzIGJ5IFBPQSIsIA0KICAgICAgICAgICAgICBzaG93X2NvdW50ID0gVCwgZmlsbF9jb2wgPSAiZGVlcHNreWJsdWUiKQ0KYGBgDQoNCg0KIyMjIFN1cGVybWFya2V0cw0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0Kbl9wb2lfYnlfUE9BICU+JSANCiAgZmlsdGVyKFBPQV9OQU1FMTYgIT0gIlVua25vd24iKSAlPiUgDQogICMgZ2F0aGVyKGtleSwgdmFsdWUsIC1QT0FfTkFNRTE2KSAlPiUgDQogIHNlbGVjdChQT0FfTkFNRTE2LCBuX3N1cGVybWFya2V0cykgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKFBPQV9OQU1FMTYsIG5fc3VwZXJtYXJrZXRzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3N1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICAiTnVtYmVyIG9mIHN1cGVybWFya2V0cyBieSBQT0EiLCANCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGZpbGxfY29sID0gImRhcmtncmVlbiIpDQpgYGANCg0KDQojIyMgU2hvcHBpbmcgY2VudHJlcw0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0Kbl9wb2lfYnlfUE9BICU+JSANCiAgZmlsdGVyKFBPQV9OQU1FMTYgIT0gIlVua25vd24iKSAlPiUgDQogICMgZ2F0aGVyKGtleSwgdmFsdWUsIC1QT0FfTkFNRTE2KSAlPiUgDQogIHNlbGVjdChQT0FfTkFNRTE2LCBuX3Nob3BwaW5nQ2VudHJlcykgJT4lIA0KICBtdXRhdGUoUE9BX05BTUUxNiA9IGZjdF9yZW9yZGVyKFBPQV9OQU1FMTYsIG5fc2hvcHBpbmdDZW50cmVzKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3Nob3BwaW5nQ2VudHJlcyIsIA0KICAgICAgICAgICAgICAiTnVtYmVyIG9mIHNob3BwaW5nIGNlbnRyZXMgYnkgUE9BIiwgDQogICAgICAgICAgICAgIHNob3dfY291bnQgPSBULCBmaWxsX2NvbCA9ICJibGFjayIpDQpgYGANCg0KIyMjIFB1YmxpYyB0cmFuc3BvcnRzDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQpuX3BvaV9ieV9QT0EgJT4lIA0KICBmaWx0ZXIoUE9BX05BTUUxNiAhPSAiVW5rbm93biIpICU+JSANCiAgIyBnYXRoZXIoa2V5LCB2YWx1ZSwgLVBPQV9OQU1FMTYpICU+JSANCiAgc2VsZWN0KFBPQV9OQU1FMTYsIG5fcHVibGljVHJhbnNwb3J0cyApICU+JSANCiAgbXV0YXRlKFBPQV9OQU1FMTYgPSBmY3RfcmVvcmRlcihQT0FfTkFNRTE2LCBuX3B1YmxpY1RyYW5zcG9ydHMgKSkgJT4lIA0KICBwbG90X21hcF9UTChTWURfUE9BLCAiUE9BX05BTUUxNiIsICJuX3B1YmxpY1RyYW5zcG9ydHMiLCANCiAgICAgICAgICAgICAgIk51bWJlciBvZiBwdWJsaWMgdHJhbnNwb3J0cyBieSBQT0EiLCANCiAgICAgICAgICAgICAgc2hvd19jb3VudCA9IFQsIGZpbGxfY29sID0gImRhcmtvcmFuZ2UiKQ0KYGBgDQoNCiMgQ2Vuc3VzIGRhdGEgbWFwcGluZw0KDQpgYGB7ciwgZmlnLndpZHRoPTguNSwgZmlnLmhlaWdodD0xMH0NCnBsb3RfY2Vuc3VzX21hcCA8LSBmdW5jdGlvbihWQVIsIENPTE9SKSB7DQogIGNlbnN1c19mZWF0dXJlX2J5X1BPQSAlPiUgDQogIG11dGF0ZShhY3Jvc3MoLVBPQV9DT0RFXzIwMTYsIH5yb3VuZCgueCwgMSkpKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gYXMuY2hhcmFjdGVyKFBPQV9DT0RFXzIwMTYpKSAlPiUgDQogIG11dGF0ZShQT0FfTkFNRTE2ID0gZmN0X3Jlb3JkZXIoYXMuZmFjdG9yKFBPQV9OQU1FMTYpLCAuZGF0YVtbVkFSXV0pKSAlPiUgDQogIHBsb3RfbWFwX1RMKFNZRF9QT0EsICJQT0FfTkFNRTE2IiwgVkFSLCANCiAgICAgICAgICAgcGFzdGUwKFZBUiwgIiBieSBQT0EgKFNZRCkiKSwgZmlsbF9jb2wgPSBDT0xPUiwgDQogICAgICAgICAgIHNob3dfY291bnQgPSBGLCBsYWJlbF9zaXplID0gMiwgcmV0dXJuX29iaiA9ICJtYXAiKQ0KfQ0KDQpncmlkLmFycmFuZ2UoDQpwbG90X2NlbnN1c19tYXAoImhpZ2hfaW5jb21lIiwgImRhcmtvcmFuZ2UiKQ0KLHBsb3RfY2Vuc3VzX21hcCgicF9pbmNvbWUiLCAiZ3JleTIzIikNCixwbG90X2NlbnN1c19tYXAoImNoaW5lc2VfcCIsICJkYXJrcmVkIikNCixwbG90X2NlbnN1c19tYXAoIm5vbl9lbmdsaXNoX24iLCAiZGFya2dyZWVuIikNCixwbG90X2NlbnN1c19tYXAoInJlbnRfZGlzdHJlc3MiLCAiZGFya2JsdWUiKQ0KLHBsb3RfY2Vuc3VzX21hcCgidW5pdCIsICJkZWVwc2t5Ymx1ZSIpDQosIG5jb2w9MikNCmBgYA0KDQoNCiMgR3Jhdml0eQ0KIyMgU291dGggRWFzdGVybiBTWUQgKDIwMjYpIHsudGFic2V0fQ0KIyMjIFJhZGlhbCBkaXN0YW5jZQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5faG9zcGl0YWxzIikgKyANCiAgeGxpbSgxNTEuMSwxNTEuMzMpICsgeWxpbSgtMzQsLTMzLjcpIHwgDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9zY2hvb2xzIikgKyANCiAgeGxpbSgxNTEuMSwxNTEuMzMpICsgeWxpbSgtMzQsLTMzLjcpIHwNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3N1cGVybWFya2V0cyIpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KQ0KKSAvDQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9zaG9wcGluZ0NlbnRyZXMiKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3B1YmxpY1RyYW5zcG9ydHMiKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykgfCANCm5fcG9pX2J5X1BPQSAlPiUgDQogIG11dGF0ZShjb21iaW5lZF9pbmRleCA9IA0KICAgICAgICAgICBub3JtYWxpc2VkX25faG9zcGl0YWxzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3NjaG9vbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc3VwZXJtYXJrZXRzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3Nob3BwaW5nQ2VudHJlcyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9wdWJsaWNUcmFuc3BvcnRzDQogICkgJT4lIHBsb3RfZ3Jhdml0eV9tYXBfVEwoIjIwMjYiLCAiY29tYmluZWRfaW5kZXgiKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykNCikNCmBgYA0KIyMjIFRyYXZlbCB0aW1lIGRpc3RhbmNlDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9ob3NwaXRhbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgKyANCiAgeGxpbSgxNTEuMSwxNTEuMzMpICsgeWxpbSgtMzQsLTMzLjcpIHwgDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9zY2hvb2xzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KSB8DQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9zdXBlcm1hcmtldHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgKyANCiAgeGxpbSgxNTEuMSwxNTEuMzMpICsgeWxpbSgtMzQsLTMzLjcpDQopIC8NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3Nob3BwaW5nQ2VudHJlcyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKSArIA0KICB4bGltKDE1MS4xLDE1MS4zMykgKyB5bGltKC0zNCwtMzMuNykgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3B1YmxpY1RyYW5zcG9ydHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgKyANCiAgeGxpbSgxNTEuMSwxNTEuMzMpICsgeWxpbSgtMzQsLTMzLjcpIHwgDQpuX3BvaV9ieV9QT0EgJT4lIA0KICBtdXRhdGUoY29tYmluZWRfaW5kZXggPSANCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX2hvc3BpdGFscyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zY2hvb2xzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3N1cGVybWFya2V0cyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zaG9wcGluZ0NlbnRyZXMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fcHVibGljVHJhbnNwb3J0cw0KICApICU+JSBwbG90X2dyYXZpdHlfbWFwX1RMKCIyMDI2IiwgImNvbWJpbmVkX2luZGV4IiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpICsgDQogIHhsaW0oMTUxLjEsMTUxLjMzKSArIHlsaW0oLTM0LC0zMy43KQ0KKQ0KYGBgDQoNCiMjIFdlc3Rlcm4gU1lEICgyMTQ1KSB7LnRhYnNldH0NCiMjIyBSYWRpYWwgZGlzdGFuY2UNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX2hvc3BpdGFscyIpIHwgDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9zY2hvb2xzIikgfA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5fc3VwZXJtYXJrZXRzIikNCikgLw0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5fc2hvcHBpbmdDZW50cmVzIikgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3B1YmxpY1RyYW5zcG9ydHMiKSB8IA0Kbl9wb2lfYnlfUE9BICU+JSANCiAgbXV0YXRlKGNvbWJpbmVkX2luZGV4ID0gDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9ob3NwaXRhbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2Nob29scyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zdXBlcm1hcmtldHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc2hvcHBpbmdDZW50cmVzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3B1YmxpY1RyYW5zcG9ydHMNCiAgKSAlPiUgcGxvdF9ncmF2aXR5X21hcF9UTCgiMjE0NSIsICJjb21iaW5lZF9pbmRleCIpDQopDQpgYGANCiMjIyBUcmF2ZWwgdGltZSBkaXN0YW5jZQ0KDQpgYGB7ciwgZmlnLndpZHRoPTkuNSwgZmlnLmhlaWdodD03fQ0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5faG9zcGl0YWxzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpIHwgDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9zY2hvb2xzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpIHwNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3N1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KKSAvDQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9zaG9wcGluZ0NlbnRyZXMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgfCANCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3B1YmxpY1RyYW5zcG9ydHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgfCANCm5fcG9pX2J5X1BPQSAlPiUgDQogIG11dGF0ZShjb21iaW5lZF9pbmRleCA9IA0KICAgICAgICAgICBub3JtYWxpc2VkX25faG9zcGl0YWxzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3NjaG9vbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc3VwZXJtYXJrZXRzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3Nob3BwaW5nQ2VudHJlcyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9wdWJsaWNUcmFuc3BvcnRzDQogICkgJT4lIHBsb3RfZ3Jhdml0eV9tYXBfVEwoIjIxNDUiLCAiY29tYmluZWRfaW5kZXgiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCikNCmBgYA0KDQojIyBOb3RoZXJuIFNZRCAoMjEwNykgey50YWJzZXR9DQojIyMgUmFkaWFsIGRpc3RhbmNlDQoNCmBgYHtyLCBmaWcud2lkdGg9OS41LCBmaWcuaGVpZ2h0PTd9DQooDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9ob3NwaXRhbHMiKSArIA0KICB4bGltKDE1MSwxNTEuNCkgKyB5bGltKC0zMy45LC0zMy41KSB8IA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc2Nob29scyIpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpIHwNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX3N1cGVybWFya2V0cyIpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpDQopIC8NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX3Nob3BwaW5nQ2VudHJlcyIpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpIHwgDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9wdWJsaWNUcmFuc3BvcnRzIikgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkgfCANCm5fcG9pX2J5X1BPQSAlPiUgDQogIG11dGF0ZShjb21iaW5lZF9pbmRleCA9IA0KICAgICAgICAgICBub3JtYWxpc2VkX25faG9zcGl0YWxzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3NjaG9vbHMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fc3VwZXJtYXJrZXRzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3Nob3BwaW5nQ2VudHJlcyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9wdWJsaWNUcmFuc3BvcnRzDQogICkgJT4lIHBsb3RfZ3Jhdml0eV9tYXBfVEwoIjIxMDciLCAiY29tYmluZWRfaW5kZXgiKSArIA0KICB4bGltKDE1MSwxNTEuNCkgKyB5bGltKC0zMy45LC0zMy41KQ0KKQ0KYGBgDQojIyMgVHJhdmVsIHRpbWUgZGlzdGFuY2UNCg0KYGBge3IsIGZpZy53aWR0aD05LjUsIGZpZy5oZWlnaHQ9N30NCigNCnBsb3RfZ3Jhdml0eV9tYXBfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX2hvc3BpdGFscyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKSArIA0KICB4bGltKDE1MSwxNTEuNCkgKyB5bGltKC0zMy45LC0zMy41KSB8IA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc2Nob29scyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKSArIA0KICB4bGltKDE1MSwxNTEuNCkgKyB5bGltKC0zMy45LC0zMy41KSB8DQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9zdXBlcm1hcmtldHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkgKyANCiAgeGxpbSgxNTEsMTUxLjQpICsgeWxpbSgtMzMuOSwtMzMuNSkNCikgLw0KKA0KcGxvdF9ncmF2aXR5X21hcF9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc2hvcHBpbmdDZW50cmVzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpIHwgDQpwbG90X2dyYXZpdHlfbWFwX1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9wdWJsaWNUcmFuc3BvcnRzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpIHwgDQpuX3BvaV9ieV9QT0EgJT4lIA0KICBtdXRhdGUoY29tYmluZWRfaW5kZXggPSANCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX2hvc3BpdGFscyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zY2hvb2xzICsNCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3N1cGVybWFya2V0cyArDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zaG9wcGluZ0NlbnRyZXMgKw0KICAgICAgICAgICBub3JtYWxpc2VkX25fcHVibGljVHJhbnNwb3J0cw0KICApICU+JSBwbG90X2dyYXZpdHlfbWFwX1RMKCIyMTA3IiwgImNvbWJpbmVkX2luZGV4IiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpICsgDQogIHhsaW0oMTUxLDE1MS40KSArIHlsaW0oLTMzLjksLTMzLjUpDQopDQpgYGANCg0KIyBTdWdnZXN0ZWQgImhpZ2gtcmlzayIgYXJlYQ0KIyMgU291dGggRWFzdGVybiBTWUQgKDIwMjYpDQoNCmBgYHtyfQ0KYmluZF9yb3dzKA0KY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9ob3NwaXRhbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCixjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3NjaG9vbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCixjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjAyNiIsICJuX3N1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KLGNhbGNfZ3Jhdml0eV9UTChuX3BvaV9ieV9QT0EsICIyMDI2IiwgIm5fc2hvcHBpbmdDZW50cmVzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQosY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIwMjYiLCAibl9wdWJsaWNUcmFuc3BvcnRzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQopICU+JSANCiAgZ3JvdXBfYnkodGFyZ2V0LCBzb3VyY2UpICU+JSANCiAgc3VtbWFyaXNlKHJpc2tfZmFjdG9yID0gc3VtKGdyYXZpdHlfcmFuaykpICU+JSANCiAgIyBzbGljZV9tYXgocmlza19mYWN0b3IsIG49MTEpICU+JSANCiAgIyBwZGYoKQ0KICANCiAgbGVmdF9qb2luKA0KICAgIGNvbmZpcm1lZF9jYXNlcyAlPiUgDQogICAgICBmaWx0ZXIobm90aWZpY2F0aW9uX2RhdGUgPCB5bWQoMjAyMDA3MDEpKSAlPiUgDQogICAgICBjb3VudChwb3N0Y29kZSwgbmFtZSA9ICJ0b3RhbF9jYXNlcyIpICU+JSANCiAgICAgIG11dGF0ZShzb3VyY2UgPSBhcy5jaGFyYWN0ZXIocG9zdGNvZGUpKSwgDQogICAgYnk9InNvdXJjZSINCiAgKSAlPiUgDQogIG11dGF0ZSh0ZXh0X2xhYiA9IGlmZWxzZSh0b3RhbF9jYXNlcyA+PSAzMCwgc291cmNlLCBOQSkpICU+JSANCiAgZ2dwbG90KGFlcyh4PXJpc2tfZmFjdG9yLCB5PXRvdGFsX2Nhc2VzKSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIHN0YXRfc21vb3RoKCkgKyANCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbD10ZXh0X2xhYikpICsgDQogIGxhYnMoc3VidGl0bGUgPSAiQmFzZWQgb24gdG90YWwgY2FzZXMgYmVmb3JlIGRhdGUgMjAyMC0wNy0wMSIpICsgDQogIGdnbChiYXNlX3NpemU9MTIpDQpgYGANCiMjIFdlc3Rlcm4gU1lEICgyMTQ1KQ0KDQpgYGB7cn0NCmJpbmRfcm93cygNCmNhbGNfZ3Jhdml0eV9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5faG9zcGl0YWxzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQosY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9zY2hvb2xzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQosY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIxNDUiLCAibl9zdXBlcm1hcmtldHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCixjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjE0NSIsICJuX3Nob3BwaW5nQ2VudHJlcyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KLGNhbGNfZ3Jhdml0eV9UTChuX3BvaV9ieV9QT0EsICIyMTQ1IiwgIm5fcHVibGljVHJhbnNwb3J0cyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KKSAlPiUgDQogIGdyb3VwX2J5KHRhcmdldCwgc291cmNlKSAlPiUgDQogIHN1bW1hcmlzZShyaXNrX2ZhY3RvciA9IHN1bShncmF2aXR5X3JhbmspKSAlPiUgDQogICMgc2xpY2VfbWF4KHJpc2tfZmFjdG9yLCBuPTExKSAlPiUNCiAgIyBwZGYoKQ0KICBsZWZ0X2pvaW4oDQogICAgY29uZmlybWVkX2Nhc2VzICU+JSANCiAgICAgIGZpbHRlcihub3RpZmljYXRpb25fZGF0ZSA+PSB5bWQoMjAyMDA3MDEpLCANCiAgICAgICAgICAgICBub3RpZmljYXRpb25fZGF0ZSA8IHltZCgyMDIwMTEwMSkpICU+JSANCiAgICAgIGNvdW50KHBvc3Rjb2RlLCBuYW1lID0gInRvdGFsX2Nhc2VzIikgJT4lIA0KICAgICAgbXV0YXRlKHNvdXJjZSA9IGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkpLCANCiAgICBieT0ic291cmNlIg0KICApICU+JSANCiAgbXV0YXRlKHRleHRfbGFiID0gaWZlbHNlKHRvdGFsX2Nhc2VzID49IDE1LCBzb3VyY2UsIE5BKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9cmlza19mYWN0b3IsIHk9dG90YWxfY2FzZXMpKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgc3RhdF9zbW9vdGgoKSArIA0KICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPXRleHRfbGFiKSkgKyANCiAgbGFicyhzdWJ0aXRsZSA9ICJCYXNlZCBvbiB0b3RhbCBjYXNlcyBiZXR3ZWVuIGRhdGUgMjAyMC0wNy0wMSBhbmQgMjAyMC0xMi0wMSIpICsgDQogIGdnbChiYXNlX3NpemU9MTIpDQpgYGANCg0KIyMgTm90aGVybiBTWUQgKDIxMDcpDQoNCmBgYHtyfQ0KYmluZF9yb3dzKA0KY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9ob3NwaXRhbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCixjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX3NjaG9vbHMiLCANCiAgICAgICAgICAgICAgICAgICAgZGlzdF9tYXRyaXggPSBTWURfUE9BX21hcGRpc3QgJT4lIG11dGF0ZShkaXN0ID0gZGlzdC8xMDAwKSkNCixjYWxjX2dyYXZpdHlfVEwobl9wb2lfYnlfUE9BLCAiMjEwNyIsICJuX3N1cGVybWFya2V0cyIsIA0KICAgICAgICAgICAgICAgICAgICBkaXN0X21hdHJpeCA9IFNZRF9QT0FfbWFwZGlzdCAlPiUgbXV0YXRlKGRpc3QgPSBkaXN0LzEwMDApKQ0KLGNhbGNfZ3Jhdml0eV9UTChuX3BvaV9ieV9QT0EsICIyMTA3IiwgIm5fc2hvcHBpbmdDZW50cmVzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQosY2FsY19ncmF2aXR5X1RMKG5fcG9pX2J5X1BPQSwgIjIxMDciLCAibl9wdWJsaWNUcmFuc3BvcnRzIiwgDQogICAgICAgICAgICAgICAgICAgIGRpc3RfbWF0cml4ID0gU1lEX1BPQV9tYXBkaXN0ICU+JSBtdXRhdGUoZGlzdCA9IGRpc3QvMTAwMCkpDQopICU+JSANCiAgZ3JvdXBfYnkodGFyZ2V0LCBzb3VyY2UpICU+JSANCiAgc3VtbWFyaXNlKHJpc2tfZmFjdG9yID0gc3VtKGdyYXZpdHlfcmFuaykpICU+JSANCiAgIyBzbGljZV9tYXgocmlza19mYWN0b3IsIG49MTEpICU+JSANCiAgIyBwZGYoKQ0KICBsZWZ0X2pvaW4oDQogICAgY29uZmlybWVkX2Nhc2VzICU+JSANCiAgICAgIGZpbHRlcihub3RpZmljYXRpb25fZGF0ZSA+PSB5bWQoMjAyMDExMDEpKSAlPiUgDQogICAgICBjb3VudChwb3N0Y29kZSwgbmFtZSA9ICJ0b3RhbF9jYXNlcyIpICU+JSANCiAgICAgIG11dGF0ZShzb3VyY2UgPSBhcy5jaGFyYWN0ZXIocG9zdGNvZGUpKSwgDQogICAgYnk9InNvdXJjZSINCiAgKSAlPiUgDQogIG11dGF0ZSh0ZXh0X2xhYiA9IGlmZWxzZSh0b3RhbF9jYXNlcyA+PSAxNSwgc291cmNlLCBOQSkpICU+JSANCiAgZ2dwbG90KGFlcyh4PXJpc2tfZmFjdG9yLCB5PXRvdGFsX2Nhc2VzKSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIHN0YXRfc21vb3RoKCkgKyANCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbD10ZXh0X2xhYikpICsNCiAgbGFicyhzdWJ0aXRsZSA9ICJCYXNlZCBvbiB0b3RhbCBjYXNlcyBhZnRlciBkYXRlIDIwMjAtMTItMDEiKSArIA0KICBnZ2woYmFzZV9zaXplPTEyKQ0KYGBgDQoNCiMgR3Jhdml0eSBwYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KU1lEX1BPQV9tYXBkaXN0ICU+JSANCiAgZmlsdGVyKHRhcmdldCA9PSAiMjE0NSIpICU+JSANCiAgbGVmdF9qb2luKG5fcG9pX2J5X1BPQSwgYnk9Yygic291cmNlIj0iUE9BX05BTUUxNiIpKSAlPiUgDQogIGxlZnRfam9pbihuX3BvaV9ieV9QT0EgJT4lIGZpbHRlcihQT0FfTkFNRTE2ID09ICIyMTQ1IiksIA0KICAgICAgICAgICAgc3VmZml4ID0gYygiIiwiX3RhcmdldCIpLCANCiAgICAgICAgICAgIGJ5PWMoInRhcmdldCI9IlBPQV9OQU1FMTYiKSkgJT4lIA0KICBsZWZ0X2pvaW4oY29uZmlybWVkX2Nhc2VzICU+JSANCiAgICAgICAgICAgICAgZmlsdGVyKG5vdGlmaWNhdGlvbl9kYXRlID49IHltZCgyMDIwMDcwMSksIA0KICAgICAgICAgICAgICAgICAgICAgbm90aWZpY2F0aW9uX2RhdGUgPCB5bWQoMjAyMDExMDEpKSAlPiUgDQogICAgICAgICAgICAgIGNvdW50KHBvc3Rjb2RlLCBuYW1lPSJUb3RhbF9jYXNlcyIpICU+JSANCiAgICAgICAgICAgICAgbXV0YXRlKHNvdXJjZSA9IGFzLmNoYXJhY3Rlcihwb3N0Y29kZSkpLCBieT0ic291cmNlIikgJT4lIA0KICBtdXRhdGUodG90YWxfbm9ybWFsaXNlZF9tYXNzX3NvdXJjZSA9IA0KICAgICAgICAgICBub3JtYWxpc2VkX25faG9zcGl0YWxzICsgDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zY2hvb2xzICsgDQogICAgICAgICAgIG5vcm1hbGlzZWRfbl9zdXBlcm1hcmtldHMgKyANCiAgICAgICAgICAgbm9ybWFsaXNlZF9uX3Nob3BwaW5nQ2VudHJlcyArIA0KICAgICAgICAgICBub3JtYWxpc2VkX25fcHVibGljVHJhbnNwb3J0cykgJT4lIA0KDQogIGxtKGxvZyhUb3RhbF9jYXNlcyArIDAuMDEpIH4gDQogICAgICAgIyBsb2codG90YWxfbm9ybWFsaXNlZF9tYXNzX3NvdXJjZSArIDAuMDEpICsgDQogICAgICAgbG9nKG5faG9zcGl0YWxzICsgMC4wMSkgKw0KICAgICAgIGxvZyhuX3NjaG9vbHMgKyAwLjAxKSArDQogICAgICAgbG9nKG5fc3VwZXJtYXJrZXRzICsgMC4wMSkgKw0KICAgICAgIGxvZyhuX3Nob3BwaW5nQ2VudHJlcyArIDAuMDEpICsNCiAgICAgICBsb2cobl9wdWJsaWNUcmFuc3BvcnRzICsgMC4wMSkgKw0KICAgICAgIGxvZyhuX2hvc3BpdGFscyArIDAuMDEpICsNCiAgICAgICBsb2coZGlzdCArIDAuMDEpLCBkYXRhPS4pICU+JSANCiAgc3VtbWFyeSgpDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=